Node.js

Lesson 08

Graceful shutdown and process signals

Stop accepting work and close resources when the process receives shutdown signals.

Good Code

src/shutdown.ts
import type { Server } from "node:http";

export function installShutdown(server: Server, closeDatabase: () => Promise<void>) {
  async function shutdown(signal: string) {
    console.info("Received " + signal + ", shutting down");

    server.close(async () => {
      await closeDatabase();
      process.exit(0);
    });

    setTimeout(() => {
      console.error("Shutdown timed out");
      process.exit(1);
    }, 10_000).unref();
  }

  process.once("SIGTERM", () => shutdown("SIGTERM"));
  process.once("SIGINT", () => shutdown("SIGINT"));
}

Bad Code

src/server.ts
process.on("SIGTERM", () => {
  process.exit(0);
});

process.on("SIGINT", () => {
  process.exit(0);
});

Review Notes

What to review

Good Code

The good version stops accepting new HTTP work, closes dependencies, and keeps a timeout in case shutdown hangs.

Bad Code

The bad version exits immediately, which can drop in-flight requests and leave external work half-complete.

Takeaways

  • A production Node process should drain HTTP and dependency connections before exit.