Shutdown is a protocol: stop admission, drain owned work, then exit within the platform’s termination window.
Graceful HTTP Shutdown
Termination is an admission-control transition followed by a bounded drain.
let draining = false
app.get('/ready', (_, res) => res.sendStatus(draining ? 503 : 204))
process.on('SIGTERM', () => {
draining = true
server.close((error) => process.exit(error ? 1 : 0))
setTimeout(() => process.exit(1), 25_000).unref()
})Invariant: No new work is accepted after readiness fails; in-flight work gets a bounded drain window.
Use when: A deploy should drain in-flight requests before the process exits.
Why this boundary matters
Stopping the process before removing it from admission interrupts requests; draining forever blocks rollout. The protocol makes both boundaries explicit.
Failure policy
| Boundary | Action |
|---|---|
| SIGTERM received | Fail readiness before beginning the drain |
| In-flight request | Allow completion inside the drain window |
| New request | Reject or route it to a healthy replica |
| Drain deadline reached | Exit non-zero and let the platform recover |
| Long-running work | Checkpoint or hand it to a durable worker before shutdown |
Trade-offs
Long drains reduce interrupted work but slow deployments and consume terminating capacity. Short drains increase retries and ambiguous outcomes. The platform termination grace period is the hard upper bound.
Decision rule: Drain only work the process can finish safely; durable work should be reclaimable by another owner.