Graceful HTTP Server Termination
http-terminator provides a robust solution for gracefully shutting down Node.js HTTP(S) servers. Unlike the native `server.close()` method, which simply stops accepting new connections but leaves existing connections open indefinitely (potentially hanging due to keep-alive or long-running requests), this library actively tracks and terminates all connections after a configurable timeout. It ensures that in-flight requests complete their responses and communicates shutdown intent to clients. The current stable version is `3.2.0`, with a release cadence that includes minor and patch updates every few months, reflecting ongoing maintenance and feature additions. Key differentiators include its explicit handling of all connection types, including `http`, `https`, and `http2` servers (since v3.2.0), and its rewrite to TypeScript in v3.0.0, providing robust type definitions.
Common errors
-
Error [ERR_REQUIRE_ESM]: require() of ES Module .../node_modules/http-terminator/dist/index.js from ... not supported.
cause `http-terminator` v3+ is an ES Module, but you are trying to import it using CommonJS `require()` syntax.fixChange your import statement to `import { createHttpTerminator } from 'http-terminator';` and ensure your project is configured for ESM (e.g., `"type": "module"` in `package.json`). -
Server is not shutting down, processes are hanging after receiving termination signals (SIGTERM/SIGINT).
cause You are likely calling the native `server.close()` method or no termination logic at all, which does not handle existing connections.fixImplement graceful shutdown using `http-terminator.terminate()` in your `SIGTERM`/`SIGINT` handlers, ensuring `httpTerminator` is initialized with your `http.Server` instance. -
UnhandledPromiseRejectionWarning: Error: Server termination timed out. Some connections may have been forcefully closed.
cause The `gracefulTerminationTimeout` period expired before all active HTTP connections could complete their requests or close naturally.fixIncrease the `gracefulTerminationTimeout` option when calling `createHttpTerminator()` to allow more time for requests to finish, or investigate why requests are taking so long.
Warnings
- breaking Version 3.0.0 migrated the entire codebase from Flow to TypeScript. This may require adjustments in projects that rely on Flow types or the internal structure of the package.
- breaking Support for Node.js v10 was dropped in version 3.1.0, raising the minimum required Node.js version to v12 (though the package.json specifies `>=14`).
- gotcha Calling `server.close()` directly on an `http.Server` instance will stop it from accepting new connections but will not forcefully close existing ones, leading to potential indefinite hangs, especially with keep-alive connections.
- gotcha Since version 3.0.0, `http-terminator` is primarily an ESM (ECMAScript Module) package. Attempting to use `require()` in a CommonJS module might lead to import errors in some Node.js environments or configurations.
- gotcha The `gracefulTerminationTimeout` option defaults to 5000 milliseconds (5 seconds). If your server has long-running requests or slow external dependencies, this default might be too short, leading to connections being forcefully closed prematurely.
Install
-
npm install http-terminator -
yarn add http-terminator -
pnpm add http-terminator
Imports
- createHttpTerminator
const createHttpTerminator = require('http-terminator');import { createHttpTerminator } from 'http-terminator'; - HttpTerminatorType
import { HttpTerminatorType } from 'http-terminator';import type { HttpTerminatorType } from 'http-terminator'; - HttpTerminatorConfigurationInputType
import type { HttpTerminatorConfigurationInputType } from 'http-terminator';
Quickstart
import http from 'http';
import { createHttpTerminator } from 'http-terminator';
const server = http.createServer((req, res) => {
console.log(`Received request: ${req.method} ${req.url}`);
// Simulate some async work that might take time
setTimeout(() => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!\n');
}, Math.random() * 1000 + 500); // Between 0.5s and 1.5s
});
server.listen(3000, () => {
console.log('Server listening on port 3000. Try curl http://localhost:3000');
});
const httpTerminator = createHttpTerminator({
server,
gracefulTerminationTimeout: 10000 // Allow up to 10 seconds for requests to complete
});
async function gracefulShutdown() {
console.log('Initiating graceful shutdown...');
try {
await httpTerminator.terminate();
console.log('Server gracefully terminated. All connections closed.');
process.exit(0);
} catch (error) {
console.error('Error during graceful shutdown:', error);
process.exit(1);
}
}
// Handle OS signals for graceful shutdown
process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);
console.log('Press Ctrl+C or send SIGTERM to shut down gracefully.');