Predictable process under SIGTERM, observable and with limits. Language: golang. HTTP: golang-apis. General: production-readiness. Rust mirror: rust-axum-production.
Boot and config
- Env (or file) once in
main. Typed struct; fail if missingDATABASE_URL/ secret. - Do not read env in the handler.
log/slogJSON in prod; level by env (LOG_LEVEL).
APP_ENV=production
LISTEN_ADDR=0.0.0.0:8080
Process and shutdown
http.Serverown (ReadHeaderTimeout,IdleTimeout). Not justr.Run().- SIGINT/SIGTERM:
Shutdown(ctx)with timeout (e.g.: 30s). Close listeners, then DB pool. - Background goroutines with
errgroup+ ctx canceled on shutdown (golang-goroutines). ListenAndServein goroutine; themainwaits for the signal.
Health
| Endpoint | Meaning |
|---|---|
/live |
Process up |
/ready |
Critical dependencies (DB ping) |
- Liveness should not kill the pod just because the DB fluctuated for 100ms — follow the orchestrator.
- No auth; no internals in the body.
Timeouts, limits, resilience
- Timeouts in every HTTP/DB client (
context.WithTimeout). - Body limit in Gin (
MaxBytesReader/ middleware). - Retries only on transitive errors idempotent, backoff + jitter.
- Pool:
SetMaxOpenConnsaligned with instances × DB max_connections. http.Server.ErrorLog/ slog; notlog.Fatalin the handler.
Observability
slogwithrequest_id,method,path,status,latency. No PII/secrets.- Metrics (Prometheus) if the team already uses it: latency, 5xx, in-flight.
- OpenTelemetry if the repo already has it — do not add a new stack in a feature.
net/http/pprofon port internal or protected — never open on the internet.
HTTP security
- Headers:
securityproject middleware (nosniff, frame, HSTS behind TLS). - Explicit CORS. Trusted proxy (
SetTrustedProxies) if there is a load balancer. - Panic recover in Gin → 500 + log; do not bring down the process on the request.
Build and runtime
CGO_ENABLED=0when possible. Image: skilldocker.GOMAXPROCSaligned with cgroup (automatic in recent Go /automaxprocsif already used).- Graceful in Kubernetes:
preStop+terminationGracePeriodSeconds> Shutdown timeout.
Anti-patterns
gin.Default()with colored logger in prod without slog- Without
Shutdown /debug/pprofpublic- Retry on non-idempotent POST
- Health that queries 12 dependencies and becomes an eternal false negative
Integration with other skills
- Gin:
golang-apis - SQL:
golang-sqlc - gRPC server:
grpc(same shutdown/health) - Docker:
docker - Go-live:
production-readiness
Completion criteria
http.Server+ shutdown with timeout/liveand/readycorrect- Timeouts in clients; body limits
- Structured logs without secrets
- pprof not public