HTTP Graceful Shutdown
http-graceful-shutdown is a Node.js utility library designed to ensure HTTP and HTTPS servers (including those built with frameworks like Express, Koa, and Fastify, or native Node.js http/http2) shut down cleanly and without disrupting active client connections. It manages open sockets, stops accepting new connections, and allows for the registration of custom cleanup functions (e.g., closing database connections) to execute before the server fully terminates. The library tracks all connections, gracefully communicates shutdown intent to clients, and can optionally destroy remaining sockets forcefully after a timeout. Version 3.1.16 is the current stable release, with version 3.0 being a significant update that improved internal handling while maintaining backward compatibility with 2.x. It has seen over 35 million downloads, indicating its widespread adoption for robust application termination. The release cadence appears stable, with major versions being well-tested.
Common errors
-
Server did not exit after shutdown, hanging process.
cause The `forceExit` option is set to `false`, and some asynchronous operations (e.g., open database connections, message queue consumers, scheduled timers) are preventing the Node.js event loop from clearing naturally after the HTTP server stops.fixEnsure all long-running processes and connections (like database clients, Redis, message queues) are explicitly closed within the `onShutdown` or `preShutdown` hooks. Alternatively, set `forceExit: true` (which is the default) to ensure termination after the configured timeout, or manually call `process.exit()` in your `finally` hook. -
TypeError: gracefulShutdown is not a function
cause Incorrect import style, likely attempting a named import (`import { gracefulShutdown } from 'http-graceful-shutdown';`) when the module provides a default export.fixUse the correct import statement for a default export: `import gracefulShutdown from 'http-graceful-shutdown';` for ESM, or `const gracefulShutdown = require('http-graceful-shutdown');` for CommonJS. -
UnhandledPromiseRejectionWarning: A promise was rejected with a reason that was not handled during shutdown.
cause An asynchronous cleanup function registered with `onShutdown` or `preShutdown` rejected a promise, and this rejection was not caught within the hook.fixWrap the asynchronous operations within your `onShutdown` and `preShutdown` functions in `try...catch` blocks or chain `.catch()` to handle potential rejections gracefully. While the library itself handles errors within these hooks to prevent process crashes, logging and specific error handling are your responsibility.
Warnings
- breaking Version 3.0 introduced significant internal changes for 'much better handling'. While stated as 'fully backwards compatible to version 2.x', users upgrading from 1.x or early 2.x might encounter subtle behavioral differences, especially concerning how connections are tracked or `preShutdown` hooks are invoked due to the underlying improvements.
- gotcha The library registers signal handlers (e.g., SIGINT, SIGTERM) by default. If your application or other libraries also register handlers for these signals, they might conflict, leading to unexpected shutdown behavior or preventing `http-graceful-shutdown` from taking control.
- gotcha By default, `http-graceful-shutdown` will call `process.exit(0)` after the timeout to ensure the process terminates. If your application relies on the event loop draining naturally after shutdown (e.g., for testing frameworks or other background processes), this forceful exit can abruptly terminate those operations.
- gotcha An improperly configured `timeout` can lead to either abrupt termination of active requests (if too short) or prolonged application unavailability during restarts (if too long). This timeout includes the duration of `onShutdown` and `preShutdown` hooks.
Install
-
npm install http-graceful-shutdown -
yarn add http-graceful-shutdown -
pnpm add http-graceful-shutdown
Imports
- gracefulShutdown (CommonJS)
import { gracefulShutdown } from 'http-graceful-shutdown';const gracefulShutdown = require('http-graceful-shutdown'); - gracefulShutdown (ESM)
import * as gracefulShutdown from 'http-graceful-shutdown';
import gracefulShutdown from 'http-graceful-shutdown';
- Options (TypeScript)
import type { Options } from 'http-graceful-shutdown';
Quickstart
const express = require('express');
const http = require('http');
const gracefulShutdown = require('http-graceful-shutdown');
const app = express();
app.get('/', (req, res) => {
console.log('Request received at /');
// Simulate a long-running request that might be in progress during shutdown
setTimeout(() => {
res.send('Hello from server! Shutting down soon...');
}, 2000);
});
const PORT = process.env.PORT || 3000;
const server = http.createServer(app);
server.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
console.log('Press Ctrl+C to initiate graceful shutdown.');
});
// This enables the graceful shutdown mechanism
gracefulShutdown(server, {
forceExit: true, // Default is true, causes process.exit after timeout
timeout: 10000, // how long to wait before force exiting (in ms)
// Register custom cleanup functions to run before the server fully terminates
onShutdown: async (signal) => {
console.log(`Server received ${signal}. Running cleanup...`);
// Example: Close database connections or other resources
await new Promise(resolve => setTimeout(resolve, 3000)); // Simulate async cleanup
console.log('Cleanup complete!');
},
finally: () => {
console.log('Server shutdown sequence finished. Goodbye!');
}
});