CodingNic

Process Management & Reliability

Graceful Shutdown

Process Management & Reliability 15 min read

Graceful Shutdown

Objectives

By the end of this lesson, you should be able to:

  • Explain what SIGTERM is, and when a process receives it
  • Stop a server from accepting new connections while letting in-flight requests finish
  • Explain why an abrupt process exit during a deployment is a real problem for real users

💡 Why this matters: Every deployment, restart, or scale-down event sends a running process a signal asking it to stop. A process that exits immediately drops every request it was in the middle of handling, a process that shuts down gracefully finishes them first, this is the difference a real user notices as a failed request during a routine deploy.

⚠️ A note on verification: every snippet and every output in this lesson was actually run.

What SIGTERM Is

SIGTERM is a signal, sent by the operating system, a process manager, or a deployment platform, asking a process to terminate, politely, it’s a request, not a kill, a process that ignores it will eventually receive SIGKILL, which cannot be intercepted or handled at all. Handling SIGTERM correctly is a process’s one chance to clean up before it’s forced to stop.

A Server That Shuts Down Gracefully

javascript
const express = require('express');
const app = express();

app.get('/slow', (req, res) => {
  setTimeout(() => {
    res.json({ status: 'completed slow request', pid: process.pid });
  }, 800);
});

const server = app.listen(6001, () => console.log(`Server ${process.pid} listening`));

process.on('SIGTERM', () => {
  console.log('SIGTERM received, starting graceful shutdown');
  server.close(() => {
    console.log('All in-flight requests finished, server closed');
    process.exit(0);
  });
});

server.close() does two things: it stops the server from accepting any new connections immediately, but it doesn’t force existing, in-flight requests to stop, its callback only fires once every request that was already being handled has actually finished.

Confirming It Actually Waits

text
sending SIGTERM to 7
SIGTERM received, starting graceful shutdown
{"status":"completed slow request","pid":7} <- slow request finished
All in-flight requests finished, server closed

SIGTERM was sent while /slow was still in its 800ms setTimeout, the process didn’t exit immediately, server.close()’s callback, and the eventual process.exit(0), only ran after that in-flight request actually completed and sent its response. A client mid-request during a deploy gets a real, successful response, not a dropped connection.

Why This Matters During Deployment Specifically

A rolling deploy, replacing old instances with new ones, sends SIGTERM to every old instance as part of the normal process, this happens routinely, not just during incidents. Without a graceful shutdown handler, every deploy would drop whatever requests happened to be in flight at that exact moment, with one, deploys become invisible to users, exactly the property a production deployment needs.

Try It

  1. Build the server above, send it a request to /slow, then send SIGTERM shortly after, and confirm the request completes before the process exits.
  2. Add a timeout, forcing process.exit(1) if server.close() hasn’t finished within, say, 10 seconds, and explain why a graceful shutdown handler should never wait forever.
  3. Add the same SIGTERM handler to a cluster worker (Lesson 2), and confirm it still finishes in-flight requests before that specific worker exits.
  4. Explain, in one or two sentences, the difference between SIGTERM and SIGKILL, and why only one of them can be handled in code.

Recap

  • SIGTERM asks a process to stop, giving it a chance to clean up first, SIGKILL forces termination immediately and can’t be intercepted.
  • server.close() stops new connections while letting in-flight requests finish, confirmed here with a slow request completing after SIGTERM was already sent.
  • Graceful shutdown is what makes routine deploys invisible to real users, not just a defense against unexpected crashes.

Next lesson: PM2, a process manager that restarts a crashed process automatically, tying process management together into something that runs unattended.