Deviopath › Node.js

Graceful Shutdown on SIGTERM

Hard · Servers

When you deploy a new version, the platform (Kubernetes, systemd, PM2...) sends the old Node process SIGTERM and kills it for real a bit later. A graceful shutdown avoids dropping users during that switch: stop taking new work, report "not ready" so the load balancer sends traffic to the new instances, let in-flight requests finish, then exit. If some requests take too long, close them after a timeout so the deploy does not hang. In Node that is process.on("SIGTERM", ...) plus server.close(). This is what makes zero-downtime deploys possible.

Write simulateShutdown(config, events) that returns a log. config.shutdownTimeout is in ms. The events are sorted by their time t:

- [t, "request", id, duration]: a request arrives. While running normally, accept it and log "<t> <id> accepted"; it finishes at t + duration (duration ≥ 1) and then logs "<time> <id> done". While draining, reject it: log "<t> <id> 503".

- [t, "health"]: log "<t> health 200" while running and "<t> health 503" while draining.

- [t, "sigterm"]: log "<t> SIGTERM: draining <n> in-flight", where n is the number of unfinished requests. If n is 0, log "<t> exit" right away. Otherwise start draining with a deadline at t + shutdownTimeout. A second SIGTERM while draining forces the shutdown immediately (like pressing Ctrl+C twice) and logs no SIGTERM line.

While draining, when the last in-flight request finishes, log "<time> exit". A forced shutdown (deadline reached or second SIGTERM) logs "<time> force-close <ids>" with the unfinished ids in the order they were accepted, joined with ", ", then "<time> exit". After exit, ignore everything.

At the same time T, handle things in this order: first requests finishing at T (earlier accepted first), then the deadline if it is T, then the input events at T in their order. So a request that finishes exactly at the deadline still finishes normally. After the last event, keep going until every accepted request has finished or the process has exited.

Next: Simulate the Node.js Event Loop