Graceful HTTP Server Shutdown
This `http-close` package for Node.js provides a mechanism to gracefully shut down an HTTP server by managing open TCP sockets. Currently at version 1.0.0, it appears to be a stable utility, likely in maintenance mode given its focused scope and the absence of rapid version increments. It differentiates itself by intelligently handling various socket states during `server.close()`: it destroys keep-alive sockets without active responses, sends `Connection: close` headers for requests where headers haven't been sent, and applies a configurable timeout (default 5 seconds) to pending connections. If a socket times out after `server.close()` has been called, the module intervenes to respond with a 500 status code before ending the connection for requests with unsent headers, and forcefully destroys all other remaining sockets. This ensures a clean exit for the server process, mitigating the common issue of hanging connections during shutdown.
Common errors
-
Error: server.close() callback not firing or taking too long
cause `server.close()` appears to hang or the callback takes longer than expected to execute, indicating connections are not being released.fixVerify that `httpClose` is correctly applied to your `http.Server` instance. Ensure you've set an appropriate `timeout` option that allows pending requests to complete while also forcing closure within acceptable bounds. Long-running requests might still delay shutdown until their timeout is reached. -
Client received unexpected 500 Internal Server Error during server shutdown
cause During graceful shutdown, `http-close` sends a 500 status code to pending requests where HTTP headers have not yet been sent, if the socket times out.fixThis is expected behavior for requests that cannot complete within the specified `httpClose` timeout during shutdown. Inform clients about scheduled maintenance periods, or increase the `timeout` if these requests are critical and must always attempt to complete gracefully. -
TypeError: Cannot read properties of undefined (reading 'close') or similar errors related to `httpClose`
cause This typically occurs if the `httpClose` function is not correctly imported or required, or if `server` is not a valid `http.Server` instance when passed to `httpClose`.fixFor ESM, use `import httpClose from 'http-close';`. For CommonJS, `const httpClose = require('http-close');`. Always ensure a valid instance of `http.createServer()` result is passed as the second argument: `httpClose({ timeout: 5000 }, yourHttpServerInstance);`.
Warnings
- gotcha The `http-close` module augments the behavior of `server.close()` but does not replace it. You must still explicitly call `server.close()` on your `http.Server` instance to initiate the shutdown process; `http-close` then hooks into this event to manage active sockets.
- gotcha The default socket timeout implemented by `http-close` is 5 seconds for pending requests after `server.close()` is called. This default might be too short for applications with long-running requests or too long for scenarios requiring very rapid server shutdowns.
- gotcha This package appears to be in maintenance mode, with its latest version being 1.0.0 and no significant updates observed in recent years. While stable for its defined purpose, it may not actively address new Node.js features, HTTP protocol changes, or complex edge cases that newer, more actively maintained server shutdown solutions might cover.
- gotcha `http-close` is designed to immediately destroy any idle keep-alive sockets (i.e., those without an active HTTP response in progress) once `server.close()` is called. This is an intentional behavior to prevent the server from hanging on unused connections, but it's important to note that clients expecting persistent connections to remain open until explicitly closed by the client will have their idle connections terminated.
Install
-
npm install http-close -
yarn add http-close -
pnpm add http-close
Imports
- httpClose
import httpClose from 'http-close';
- httpClose
import { httpClose } from 'http-close'; - httpClose
const httpClose = require('http-close');
Quickstart
import http from 'http';
import httpClose from 'http-close';
const server = http.createServer((req, res) => {
// Simulate some async work that might keep the connection open
setTimeout(() => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, World!\n');
}, Math.random() * 500); // Random delay up to 500ms
});
// Add http-close hook with a custom timeout of 3 seconds
httpClose({ timeout: 3000 }, server);
server.listen(3000, () => {
console.log('Server listening on port 3000. Try hitting it with requests.');
console.log('Then, press Ctrl+C to initiate graceful shutdown.');
});
// Handle graceful shutdown on process termination signals
process.on('SIGTERM', () => {
console.log('SIGTERM received. Initiating graceful shutdown...');
server.close(() => {
console.log('Server closed. Exiting process.');
process.exit(0);
});
});
process.on('SIGINT', () => {
console.log('SIGINT received. Initiating graceful shutdown...');
server.close(() => {
console.log('Server closed. Exiting process.');
process.exit(0);
});
});