Cloud-Native Domain
Layer 3: Domain Constraints
Domain Constraints → Design Implications
Domain Rule Design Constraint Rust Implication
12-Factor Config from env Environment-based config
Observability Metrics + traces tracing + opentelemetry
Health checks Liveness/readiness Dedicated endpoints
Graceful shutdown Clean termination Signal handling
Horizontal scale Stateless design No local state
Container-friendly Small binaries Release optimization
Critical Constraints
Stateless Design
RULE: No local persistent state WHY: Pods can be killed/rescheduled anytime RUST: External state (Redis, DB), no static mut
Graceful Shutdown
RULE: Handle SIGTERM, drain connections WHY: Zero-downtime deployments RUST: tokio::signal + graceful shutdown
Observability
RULE: Every request must be traceable WHY: Debugging distributed systems RUST: tracing spans, opentelemetry export
Trace Down ↓
From constraints to design (Layer 2):
"Need distributed tracing" ↓ m12-lifecycle: Span lifecycle ↓ tracing + opentelemetry
"Need graceful shutdown" ↓ m07-concurrency: Signal handling ↓ m12-lifecycle: Connection draining
"Need health checks" ↓ domain-web: HTTP endpoints ↓ m06-error-handling: Health status
Key Crates
Purpose Crate
gRPC tonic
Kubernetes kube, kube-runtime
Docker bollard
Tracing tracing, opentelemetry
Metrics prometheus, metrics
Config config, figment
Health HTTP endpoints
Design Patterns
Pattern Purpose Implementation
gRPC services Service mesh tonic + tower
K8s operators Custom resources kube-runtime Controller
Observability Debugging tracing + OTEL
Health checks Orchestration /health , /ready
Config 12-factor Env vars + secrets
Code Pattern: Graceful Shutdown
use tokio::signal;
async fn run_server() -> anyhow::Result<()> { let app = Router::new() .route("/health", get(health)) .route("/ready", get(ready));
let addr = SocketAddr::from(([0, 0, 0, 0], 8080));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.with_graceful_shutdown(shutdown_signal())
.await?;
Ok(())
}
async fn shutdown_signal() { signal::ctrl_c().await.expect("failed to listen for ctrl+c"); tracing::info!("shutdown signal received"); }
Health Check Pattern
async fn health() -> StatusCode { StatusCode::OK }
async fn ready(State(db): State<Arc<DbPool>>) -> StatusCode { match db.ping().await { Ok() => StatusCode::OK, Err() => StatusCode::SERVICE_UNAVAILABLE, } }
Common Mistakes
Mistake Domain Violation Fix
Local file state Not stateless External storage
No SIGTERM handling Hard kills Graceful shutdown
No tracing Can't debug tracing spans
Static config Not 12-factor Env vars
Trace to Layer 1
Constraint Layer 2 Pattern Layer 1 Implementation
Stateless External state Arc for external
Graceful shutdown Signal handling tokio::signal
Tracing Span lifecycle tracing + OTEL
Health checks HTTP endpoints Dedicated routes
Related Skills
When See
Async patterns m07-concurrency
HTTP endpoints domain-web
Error handling m13-domain-error
Resource lifecycle m12-lifecycle