Global Handlers and Graceful Shutdown
1. System Overview
initGlobalHandlers(options): Registers process-level event listeners for crashes and termination signalsgracefulHttpClose(server): Helper function that wraps Express server closure in a Promise with abort signal support
2. API Reference
Function: initGlobalHandlers(options)
Signature:
function initGlobalHandlers(options = {})Initializes process-level event handlers that listen for fatal errors and termination signals. This function should be called once at application startup, typically immediately after creating the Express server.
Function: gracefulHttpClose(server)
Signature:
function gracefulHttpClose(server)Returns an async function that gracefully closes an Express/HTTP server with AbortSignal support. When called, the returned function stops accepting new connections and waits for existing connections to complete.
Parameters:
server: Express or Node.js HTTP server instance
Returns: An async function (signal) => Promise<void> that:
- Calls
server.close(callback) - Listens to
signal.addEventListener('abort', forceClose)for timeout - Resolves when server closes gracefully
- Rejects if server closure fails
Callback Signatures
closeServer(signal)
Parameters:
signal:AbortSignal- Signals when timeout is exceeded
Returns: Promise<void>
onShutdown(signal)
Parameters:
signal:AbortSignal- Signals when timeout is exceeded
Returns: Promise<void>
Purpose: Execute cleanup during graceful shutdown (SIGTERM/SIGINT/SIGQUIT)
onCrash(error, signal)
Parameters:
error:Error- The error that caused the crashsignal:AbortSignal- Signals when timeout is exceeded
Returns: Promise<void>
Purpose: Execute emergency cleanup and alerting when fatal error occurs
Configuration Flags
exitOnUnhandledRejection
Default: true
Important
When set to false, the process will not exit after logging an unhandledRejection.
The onCrash callback will still NOT execute in this case.
exitOnUncaughtException
Default: true
Important
When set to false, the process will not exit after logging an exitOnUncaughtException.
The onCrash callback will still NOT execute in this case.
Note
Setting this to false is not recommended as the application state is likely corrupted after an uncaught exception.
3. Configuration Patterns
Basic Initialization
Minimal setup with no custom handlers logs errors and exits:
import { initGlobalHandlers } from 'ds-express-errors'
initGlobalHandlers();This configuration still provides value by logging uncaught errors before the process exits.
HTTP Server Shutdown
Using gracefulHttpClose to properly close the HTTP server:
import { initGlobalHandlers, gracefulHttpClose } from 'ds-express-errors'
const server = app.listen(3000);
initGlobalHandlers({
closeServer: gracefulHttpClose(server)
});The gracefulHttpClose helper ensures no new connections are accepted and existing requests complete before shutdown.
Database Cleanup
Adding database disconnection logic with onShutdown:
initGlobalHandlers({
closeServer: gracefulHttpClose(server),
onShutdown: async (signal) => {
console.log('Disconnecting database...');
await mongoose.disconnect();
}
});The onShutdown callback receives an AbortSignal parameter that indicates timeout conditions.
Crash Reporting
Using onCrash to send alerts before process termination:
initGlobalHandlers({
closeServer: gracefulHttpClose(server),
onCrash: async (err, signal) => {
await sendAlertToAdmin(err);
}
});The onCrash callback receives both the error and an AbortSignal.
Custom Timeout Configuration
Adjusting the maximum wait time for cleanup operations:
initGlobalHandlers({
closeServer: gracefulHttpClose(server),
onShutdown: async () => {
await longRunningCleanup();
},
maxTimeout: 30000 // 30 seconds instead of default 10 seconds
});The maxTimeout option controls how long the system waits before forcing shutdown.
Default is 10000ms.
Disabling Exit on Errors
Preventing automatic exit for specific error types:
initGlobalHandlers({
exitOnUnhandledRejection: false,
exitOnUncaughtException: true
});Important
Setting exitOnUnhandledRejection or exitOnUncaughtException to false causes the system to log the error without terminating the process.
This is generally not recommended for production.
4. Complete Usage Example
import express from 'express'
import { initGlobalHandlers, gracefulHttpClose } from 'ds-express-errors'
import mongoose from 'mongoose';
const app = express()
const server = app.listen(3000)
// Initialize global handlers with all options
initGlobalHandlers({
closeServer: gracefulHttpClose(server),
onShutdown: async (signal) => {
console.log('Graceful shutdown initiated')
await mongoose.disconnect()
console.log('Database disconnected')
},
onCrash: async (err, signal) => {
console.error('Application crash:', err)
await sendAlertToSlack(err)
},
exitOnUnhandledRejection: true,
exitOnUncaughtException: true,
maxTimeout: 15000 // 15 seconds
})