Install close-with-grace
mainInstall the package using npm:
npm i close-with-gracerepository·main·Indexed 43 days ago
https://github.com/mcollina/close-with-graceA Node.js utility for graceful process shutdowns. It listens for common termination signals (like SIGINT, SIGTERM) and unhandled errors (uncaughtException, unhandledRejection), allowing developers to execute cleanup logic before the process exits. Version 2.5.0 includes features such as timeout protection via a configurable delay, custom logger injection, and the ability to skip specific process events.
Install the package using npm:
npm i close-with-graceThe callback function fn provided to closeWithGrace receives a single object containing the reason for the shutdown:
err: If the shutdown was triggered by a process error, this contains the Error object.signal: If the shutdown was triggered by a process signal (e.g., 'SIGTERM'), this contains the signal name string.manual: If the shutdown was triggered by calling the returned close() method, this is present (though the implementation uses manual: true in the run call, the object structure is passed to your function).By default, close-with-grace uses console. You can provide a custom logger object with an error method to control how internal logs are handled. Pass false to disable logging entirely.
const closeWithGrace = require('close-with-grace')
closeWithGrace(
{
delay: 500,
logger: { error: (m) => console.error(`[close-with-grace] ${m}`) }
},
async function ({ signal, err, manual }) {
if (err) {
console.error(err)
}
await closeYourServer()
})
// to disable logging at all, pass falsy value to logger option.
closeWithGrace({ logger: false }, () => await somethingUseful())When using Fastify, use the closeWithGrace callback to call app.close(). You can use the signal or err properties to log the reason for shutdown using Fastify's built-in logger.
import fastify from 'fastify'
import closeWithGrace from 'close-with-grace'
const app = fastify()
closeWithGrace(async function ({ signal, err, manual }) {
if (err) {
app.log.error({ err }, 'server closing with error')
} else {
app.log.info(`${signal} received, server closing`)
}
await app.close()
})
await app.listen()Use closeWithGrace to wrap your cleanup logic. You provide an options object (optional) and an async function (or a function using a callback) that performs the cleanup. The function receives an object containing signal, err, and manual.
const closeWithGrace = require('close-with-grace')
// delay is the number of milliseconds for the graceful close to
// finish.
closeWithGrace({ delay: 500 }, async function ({ signal, err, manual }) {
if (err) {
console.error(err)
}
await closeYourServer()
})
// default delay is 10000
// to disable delay feature at all, pass falsy value to delay option.
closeWithGrace({ delay: false }, () => await somethingUseful())You can prevent certain events from triggering the graceful shutdown by providing an array of event names to the skip option.
Warning: If you skip an event, you are responsible for handling it yourself (e.g., via process.on(...)), otherwise the process may crash or exit unexpectedly.
import closeWithGrace from 'close-with-grace'
// Handle errors separately
process.on('unhandledRejection', (err) => {
// Your custom error handling
})
closeWithGrace(
{ skip: ['unhandledRejection', 'uncaughtException'] },
async function ({ signal, err, manual }) {
await cleanupResources()
}
)The closeWithGrace function adds global listeners to several Node.js process events (including SIGINT, SIGTERM, uncaughtException, and unhandledRejection). When an event is emitted, the provided function is called. If the same event is emitted again while the function is still running, the process terminates abruptly.
opts (Object)delay (number): Milliseconds to wait before abruptly closing the process. Default: 10000. Pass false, null, or undefined to disable.logger (Object): Logger instance with an error method. Default: console. Pass false, null, or undefined to disable.skip (Array<string>): Event names to skip from triggering the callback. Default: [].onSecondError(error) (Function): Callback executed if an uncaughtException or unhandledRejection occurs while the cleanup function is executing.onSecondSignal(signal) (Function): Callback executed if another signal is received while the cleanup function is executing.onTimeout(delay) (Function): Callback executed if the cleanup function fails to complete within the specified delay.Note: onSecondError, onSecondSignal, and onTimeout callbacks cannot perform asynchronous operations because process.exit(1) is invoked immediately after they return.
fn({ err, signal, manual } [, cb]) (Function)Promise or use a callback.0.Error, the process exits with code 1.err: The error that triggered the shutdown (if any).signal: The signal that triggered the shutdown (if any).manual: Boolean indicating if the shutdown was triggered manually via the returned close() method.Returns an object containing:
close(): Triggers a graceful close; sets manual to true in the callback.uninstall(): Removes all global listeners added by closeWithGrace.// Signature
closeWithGrace([opts], fn({ err, signal, manual }))When calling closeWithGrace(opts, fn), the opts object supports the following configuration keys:
| Key | Type | Default | Description |
|---|---|---|---|
delay | number | 10000 | Maximum time (in milliseconds) to wait for the cleanup function to finish before forcing exit. |
logger | object or function | console | A logger object (must have an .error() method) or a function used for logging errors and timeouts. |
skip | Array<string> | [] | An array of process event names (e.g., 'SIGINT') to ignore. |
onSecondSignal | function | undefined | Callback invoked if a second signal is received during shutdown. |
onSecondError | function | undefined | Callback invoked if a second error occurs during shutdown. |
onTimeout | function | undefined | Callback invoked if the cleanup process is killed by the delay timeout. |
The closeWithGrace function manages process signals (like SIGTERM), errors, and normal exits to ensure your application can perform cleanup tasks before shutting down.
It accepts an optional configuration object and a callback function. The callback function is executed when a shutdown event occurs. The callback can be async (returning a Promise) or use a done callback to signal completion.
Key Features:
delay, the process is forcibly killed.close() to trigger shutdown manually and uninstall() to remove all event listeners.const closeWithGrace = require('close-with-grace');
const { close, uninstall } = closeWithGrace({
delay: 5000,
logger: console
}, async ({ err, signal, manual }) => {
console.log('Cleaning up...');
// Perform async cleanup here
await someCleanupTask();
console.log('Cleanup finished');
});
// To trigger shutdown manually:
// await close();
// To stop listening to process events:
// uninstall();The cleanup function passed to closeWithGrace can be implemented in two ways:
1. Async/Await (Recommended): Return a Promise that resolves when cleanup is complete.
closeWithGrace({}, async () => {
await performCleanup();
});2. Callback style:
Use the done argument provided as the second parameter to the function. Call done() with no arguments on success, or done(err) if an error occurred.
closeWithGrace({}, (out, done) => {
performCleanup((err) => {
if (err) return done(err);
done();
});
});