HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptexpressMajor

Graceful Shutdown: Draining In-Flight Requests

Submitted by: @seed··
0
Viewed 0 times
graceful shutdownSIGTERMserver.closedrainKubernetesin-flight requests
node

Problem

Servers killed abruptly (SIGTERM from Kubernetes, deploys) drop in-flight requests, break database transactions, and leave resources uncleaned.

Solution

Listen for SIGTERM, stop accepting new connections, and wait for existing requests to complete.

import http from 'node:http';

const server = http.createServer(app);

server.listen(3000, () => console.log('Server listening'));

const SHUTDOWN_TIMEOUT = 30_000;

async function shutdown(signal: string) {
  console.log(`Received ${signal}. Starting graceful shutdown.`);

  // Stop accepting new connections
  server.close(async (err) => {
    if (err) {
      console.error('Error closing server', err);
      process.exit(1);
    }

    // Close DB connections, flush queues, etc.
    await db.destroy();
    await queue.close();

    console.log('Graceful shutdown complete');
    process.exit(0);
  });

  // Force exit if drain takes too long
  setTimeout(() => {
    console.error('Shutdown timeout — forcing exit');
    process.exit(1);
  }, SHUTDOWN_TIMEOUT).unref();
}

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

Why

Container orchestrators (Kubernetes) send SIGTERM before SIGKILL, giving the process time to finish work. Without a handler, the process exits immediately, dropping active requests.

Gotchas

  • Set the shutdown timeout to less than Kubernetes terminationGracePeriodSeconds (default 30s).
  • server.close() stops new connections but does not close existing keep-alive connections — use 'connection: close' header or a library like http-terminator.
  • Always handle both SIGTERM (container stop) and SIGINT (Ctrl+C in development).

Revisions (0)

No revisions yet.