Skip to content

Instantly share code, notes, and snippets.

@hosh
Created November 24, 2025 18:27
Show Gist options
  • Select an option

  • Save hosh/3b494e47e8df7b1f0b23434a9c172d72 to your computer and use it in GitHub Desktop.

Select an option

Save hosh/3b494e47e8df7b1f0b23434a9c172d72 to your computer and use it in GitHub Desktop.
Nodejs shutdown handler
'use strict';
/* This module handles shutdown procedures to ensure a graceful shutdown
- Function to register a shutdown callbacks
- Call shutdown callbacks on uncaught promise rejections and signals
- Call the exported setup() at the top of the bootup, usually in main.ts
*/
// import your logging code here
const log = (level, message) => {
// This is a log shim. Adapt it to your logger
};
const error_types = ['unhandledRejection', 'uncaughtException']; // as NodeJS.UncaughtExceptionOrigin[];
const signal_traps = ['SIGTERM', 'SIGINT', 'SIGUSR2'] as NodeJS.Signals[];
const shutdown_handlers = [];
// This is called to register a shutdown handler. Call this from elsewhere so that
// cleanup code can be executed
export const registerShutdownHandler = (f: () => Promise<void>): void => {
shutdown_handlers.push(f);
};
const triggerShutdownHandlers = async (): Promise<void> => {
await Promise.all.forEach((x) => x() ));
log("info", "All shutdown handlers have completed. Resuming exit");
};
export const shutdownNow = (reason: string, exit_code: number): Promise<void> => {
try {
log("info", `Receiving shutdown (reason: ${reason}). Starting shutdown.`);
triggerShutdownHandlers().
then(() => { process.exit(exit_code) }).
catch((err) => {
log("error", `Error during shutdown: ${err}`);
process.exit(127);
});
} catch (_) {
process.exit(128);
}
process.exit(exit_code);
};
// Custom error handler, because this also works with unhandled rejections
const handleErrors = (...args) => {
const err = args[0];
try {
log("warn", `Uncaught exception of unhandled rejection. Error (${err}) received. Starting graceful shutdown.`);
triggerShutdownHandlers().
then(() => { process.exit(1) }).
catch((err) => {
log("error", `Error during shutdown: ${err}`);
process.exit(2);
})
} catch (_) {
process.exit(1);
}
};
// Call this once during bootup, at the top of the bootup
export const setup = () => {
log("info", "Setting up shutdown handlers");
process.on("unhandledRejection", handleErrors);
process.on("uncaughtException", handleErrors);
signal_traps.forEach(type => {
log("info", `Setting up signal trap ${type}`)
process.once(type, (_signal) => {
try {
log("warn", `Signal ${type} received. Starting graceful shutdown`);
triggerShutdownHandlers().
catch((err) => {
log("error", `Error during shutdown: ${err}`);
}).
finally(() => { process.kill(process.pid, type) }) // fire off the OS signal again
} catch (err) {
log("error", `Error during shutdown: ${err}`);
process.exit(2); // Return a different exit code to indicate an error during graceful shutdown
}
})
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment