How do you implement graceful shutdown in a Node service?

3 minadvancednodejsgraceful-shutdownsigtermsignalscleanup

Quick Answer

Listen for SIGTERM/SIGINT, stop accepting new connections (server.close), finish in-flight requests, close resources like DB pools and message consumers, then exit. Add a timeout to force-exit if cleanup hangs. This prevents dropped requests and corrupted state during deploys and container restarts.

Detailed Answer

Answer: Graceful shutdown ensures a deploy, scale-down, or Ctrl+C doesn't drop in-flight requests or leave resources dangling.

The sequence:

  1. Catch termination signals (SIGTERM from orchestrators/containers, SIGINT from Ctrl+C).
  2. Stop accepting new workserver.close() stops new connections but lets in-flight requests finish.
  3. Drain / close resources — DB pools, Redis, message-queue consumers, open files.
  4. Exit with code 0, or force-exit after a timeout if something hangs.
const server = app.listen(3000);

async function shutdown(signal) {
  console.log(`${signal} received, shutting down...`);

  // Stop accepting new connections; finish in-flight ones
  server.close(async () => {
    try {
      await db.end();          // close DB pool
      await redis.quit();      // close cache
      process.exit(0);
    } catch (err) {
      console.error('Error during shutdown', err);
      process.exit(1);
    }
  });

  // Safety net: don't hang forever
  setTimeout(() => {
    console.error('Forced shutdown after timeout');
    process.exit(1);
  }, 10_000).unref();
}

process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));

Why it matters:

  • Kubernetes sends SIGTERM then waits (terminationGracePeriodSeconds) before SIGKILL. Handling SIGTERM lets running requests complete during a rolling deploy → zero dropped requests.
  • Closing DB/queue connections cleanly avoids leaked connections and half-processed messages.
  • .unref() on the timeout ensures it doesn't itself keep the process alive.

Tip: also fail readiness checks first so the load balancer stops routing new traffic before you close the server.