Global Handlers and Graceful Shutdown


1. System Overview

  • initGlobalHandlers(options): Registers process-level event listeners for crashes and termination signals
  • gracefulHttpClose(server): Helper function that wraps Express server closure in a Promise with abort signal support

2. API Reference

Function: initGlobalHandlers(options)

Signature:

javascript
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:

javascript
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 crash
  • signal: 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 icon

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 icon

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:

javascript
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:

javascript
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:

javascript
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:

javascript
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:

javascript
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:

javascript
initGlobalHandlers({
  exitOnUnhandledRejection: false,
  exitOnUncaughtException: true
});

important icon

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

javascript
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

})