USER@L4KH4N_J
NODETLKDSK-NODE-0xA17F
CLEARANCETIER-IV
REGIONAP-SOUTH-1
WXscanning...
LIFE--Y ---D --:--:--
BUILD2026.05.23-stable
SYS--:--:--
X0000 Y0000
◂ BLOG INDEX
18 JUN 2026·1 min read

Zero-Downtime Deploys Without The Mythology

backenddevopsdistributed-systems

"Zero-downtime" sounds like a magic spell. In practice it's three boring disciplines applied consistently: backward-compatible changes, graceful shutdown, and health checks that tell the truth.

Backward-compatible first

The single biggest source of deploy outages isn't the deploy mechanism — it's a new version that can't coexist with the old one for the 30 seconds they overlap.

-- Don't do this in one deploy:
ALTER TABLE users DROP COLUMN legacy_token;
 
-- Do this across two:
-- Deploy 1: stop writing to legacy_token
-- Deploy 2: drop the column

Every schema change is two deploys. Every API change is additive until the old clients are gone.

Graceful shutdown

When the orchestrator sends SIGTERM, your process has a few seconds to stop accepting new connections and drain in-flight ones:

srv := &http.Server{Addr: ":8080"}
go srv.ListenAndServe()
 
<-ctx.Done() // SIGTERM received
shutdownCtx, cancel := context.WithTimeout(context.Background(), 25*time.Second)
defer cancel()
srv.Shutdown(shutdownCtx) // finishes live requests, refuses new ones

Health checks that don't lie

A readiness probe that returns 200 the instant the process starts is worse than no probe — it tells the load balancer to send traffic before the app can serve it. Gate readiness on the things that actually matter:

  • Database connection pool established
  • Caches warmed (if you depend on them)
  • Downstream dependencies reachable

Get those three right and "zero-downtime" stops being mythology and starts being Tuesday.