typescriptadvanced

Graceful Server Shutdown

Handle SIGTERM and SIGINT signals to drain connections, close database pools, and exit cleanly.

typescript
import http from 'http';

type CleanupFn = () => Promise<void>;

export function gracefulShutdown(
  server: http.Server,
  cleanups: CleanupFn[] = [],
  timeoutMs = 10_000
) {
  let shuttingDown = false;

  async function shutdown(signal: string) {
    if (shuttingDown) return;
    shuttingDown = true;
    console.log(`Received ${signal}, shutting down gracefully...`);

    const forceExit = setTimeout(() => {
      console.error('Forced shutdown after timeout');
      process.exit(1);
    }, timeoutMs);

    try {
      await new Promise<void>((resolve, reject) => {
        server.close((err) => (err ? reject(err) : resolve()));
      });

      for (const cleanup of cleanups) {
        await cleanup();
      }

      console.log('Shutdown complete');
      clearTimeout(forceExit);
      process.exit(0);
    } catch (err) {
      console.error('Error during shutdown:', err);
      clearTimeout(forceExit);
      process.exit(1);
    }
  }

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

// Usage:
// const server = app.listen(3000);
// gracefulShutdown(server, [
//   () => db.close(),
//   () => redis.quit(),
// ]);

Use Cases

  • Production server deployment
  • Kubernetes pod termination
  • Zero-downtime releases

Tags

Related Snippets

Similar patterns you can reuse in the same workflow.