Graceful shutdown
Before the code: what graceful shutdown actually means
Picture a restaurant at closing time. The good waiter does not yell stop and dump plates on the floor. They stop seating new guests, let the people already eating finish, then turn the lights off. That is graceful shutdown for a server. When the operating system sends a stop signal, you want the server to stop accepting new connections, let the writes already in flight finish, then quit. In Node you wire this with process.on(SIGTERM), server.close, and a small drain loop.
Stop accepting, drain, exit
Quiz: Quiz
Loading practice…
Same idea as Go's context-based shutdown, simpler API. server.close stops listening. Existing conns keep their handlers. A setInterval polls for drain.
const conns = new Set();
const server = createServer((conn) => {
conns.add(conn);
// ... data handler unchanged ...
conn.on("close", () => conns.delete(conn));
conn.on("error", () => {});
});Every live socket is tracked in a module-level Set: add on connect, delete on close. The shutdown sequence below reads conns.size to know when the last client has left.
function shutdown(signal) {
if (shuttingDown) return;
shuttingDown = true;
console.log(`\n [shutdown] ${signal} received, draining...`);
server.close(() => console.log(" [shutdown] listener closed"));
const deadline = setTimeout(() => {
console.log(" [shutdown] forced after 5s");
for (const c of conns) c.destroy();
process.exit(0);
}, 5000);
deadline.unref();
const checkDrain = setInterval(() => {
if (conns.size === 0) {
clearInterval(checkDrain);
console.log(" [shutdown] clean drain");
process.exit(0);
}
}, 100);
checkDrain.unref();
}
process.on("SIGINT", () => shutdown("SIGINT"));
process.on("SIGTERM", () => shutdown("SIGTERM"));The whole shutdown sequence. setInterval polls for drain, setTimeout caps the wait.
After 5 seconds without natural drain, we call conn.destroy() on every remaining conn (brutal close). Then process.exit. This is the production pattern Kubernetes expects.