Zero-downtime deploys in practice
🎯You'll be able to
Combine readiness checks, graceful shutdown, start-before-stop and load balancer retries so a deploy under traffic fails no requests, and measure that it did.
🏠The everyday picture
A relay race: the next runner starts moving before the baton arrives, takes it while both are running, and only then does the first runner slow down. Drop any one of those habits and the baton hits the ground.
📘What it really is
Zero downtime needs every link in the chain:
- New copies start first (
create_before_destroy, or a rolling update with surge). - New copies get traffic only when ready. RouteRani's image has a
HEALTHCHECKon/ready, and Terraform'swait = truewaits forhealthybefore moving on. nginx sends requests only to copies that answer. - Old copies stop gracefully. On
SIGTERM, the API reports not ready, finishes requests in progress, then exits (CD1 Lesson 4). - The load balancer retries. If a request reaches a copy at the moment it stops, nginx's
proxy_next_upstream error timeout http_502 http_503sends it to another copy. - The load balancer notices changes quickly. nginx re-resolves
appevery 2 seconds (CD2 Lesson 4). - It's measured. Send steady traffic through the deploy and count failures; "it looked fine" isn't evidence.
What breaks it: a health check that passes too early, an app that ignores SIGTERM, CMD npm start, a load balancer that caches addresses,
long requests cut off by the shutdown timeout, or only one copy.
📝A worked example
Input: in the finished kit, with the 1.0.1 release live, start node tools/load.js http://localhost:8080/api/routes 45 5 in one terminal and
node tools/pipeline.js 1.0.2 --skip-tests in another.
Expected output: the pipeline reports 1.0.2 is live, and the load tool reports failed: 0. On the 4-core test machine on 1 November 2026, a
run like this sent 46,478 requests during the deploy with none failed. Project 2 test 6 runs the same check and allows up to 0.5% failures,
because a busy laptop may be slower.
🌍Where it's used
- Every service with users at all hours: booking sites, banking apps, messaging.
- Platform health metrics: many teams track "errors during deploys" as a measure of their delivery process.
- Load tests in pipelines before big events, with a deploy in the middle.
📝Case scenario
A railway ticketing API showed a burst of errors at every deploy, which the team had accepted as normal for years. Measuring showed about 3% of requests failing for 20 seconds each time. Three changes fixed it: starting the app directly instead of through a shell script, a readiness check that waited for the cache to load, and load balancer retries on 502 and 503. Deploys then showed no failed requests.
🖱️Try it
Run the worked example, then repeat it with the starter's Dockerfile (CMD ["npm", "start"] and no health check) built as 1.0.9. Success: you
see a difference in the failed count, or if both show 0, you can explain which other link in the chain is protecting you.
⚠️Common mistakes
- One copy. Sign: every deploy fails some requests. Fix: at least two, and start new before stopping old.
- Not measuring. Sign: "deploys are fine" with no numbers. Fix: traffic and a failure count during every test deploy.
- No retries at the load balancer. Sign: a few errors at each deploy even with good health checks. Fix: retry safe requests on another copy.
🛠️For your project
Project 2 test 6 deploys under traffic and allows at most 0.5% failed requests; test 7 also sends traffic during a bad release and allows at most 1%.
✅Quick check
Name three things needed for a zero-downtime deploy.
Show the answer
Any three of: start new copies first, traffic only to ready copies, graceful shutdown, load balancer retries, quick discovery of changes, measurement.
Why does the API report "not ready" when it gets SIGTERM?
Show the answer
So the load balancer stops sending it new requests while it finishes the current ones.
