CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-signal-exit

Event handler that fires when a Node.js process exits regardless of how termination occurs.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

Signal Exit

Signal Exit provides a reliable way to execute cleanup code when a Node.js process exits, regardless of how the termination occurs - whether through normal completion, explicit process.exit() calls, signal handling, or fatal external signals.

Package Information

  • Package Name: signal-exit
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install signal-exit

Core Imports

import { onExit } from "signal-exit";

For CommonJS:

const { onExit } = require("signal-exit");

For signals array:

import { signals } from "signal-exit/signals";

For browser environments:

import { onExit } from "signal-exit/browser";

Basic Usage

import { onExit } from "signal-exit";

// Register an exit handler
const removeHandler = onExit((code, signal) => {
  console.log(`Process exiting with code: ${code}, signal: ${signal}`);
  // Perform cleanup operations here
});

// Remove the handler if needed
// removeHandler();

Architecture

Signal Exit is built around several key components that work together to provide reliable exit handling:

  • Signal Handler Registration: Platform-aware signal listener setup that automatically handles differences between Windows, Linux, and macOS
  • Event Emitter System: Internal event system that coordinates multiple exit handlers and ensures proper execution order
  • Process Instrumentation: Monkey-patching of process.emit and process.reallyExit to intercept all exit scenarios
  • Fallback Mechanisms: Graceful degradation when process instrumentation is not possible (browser environments, limited process objects)
  • Handler Queue Management: Dual-queue system supporting both normal and "always last" handler execution

The library uses a singleton pattern to ensure only one instance manages exit handling per process, with automatic cleanup and re-registration capabilities for complex scenarios.

Capabilities

Exit Handler Registration

Register a function to be called when the process exits for any reason.

/**
 * Called when the process is exiting, whether via signal, explicit
 * exit, or running out of stuff to do.
 *
 * If the global process object is not suitable for instrumentation,
 * then this will be a no-op.
 *
 * Returns a function that may be used to unload signal-exit.
 */
function onExit(
  cb: Handler,
  opts?: { alwaysLast?: boolean }
): () => void;

/**
 * A function that takes an exit code and signal as arguments
 *
 * In the case of signal exits *only*, a return value of true
 * will indicate that the signal is being handled, and we should
 * not synthetically exit with the signal we received. Regardless
 * of the handler return value, the handler is unloaded when an
 * otherwise fatal signal is received, so you get exactly 1 shot
 * at it, unless you add another onExit handler at that point.
 *
 * In the case of numeric code exits, we may already have committed
 * to exiting the process, for example via a fatal exception or
 * unhandled promise rejection, so it is impossible to stop safely.
 */
type Handler = (
  code: number | null | undefined,
  signal: NodeJS.Signals | null
) => true | void;

Usage Examples:

import { onExit } from "signal-exit";

// Basic cleanup handler
onExit((code, signal) => {
  console.log("Cleaning up resources...");
  // Close database connections, save files, etc.
});

// Handler that runs after all other handlers
onExit((code, signal) => {
  console.log("Final cleanup step");
}, { alwaysLast: true });

// Signal capture (prevent synthetic exit)
onExit((code, signal) => {
  if (signal === 'SIGTERM') {
    console.log("Graceful shutdown initiated");
    // Perform graceful shutdown
    return true; // Prevent synthetic process.kill
  }
});

Signal List Access

Access the array of signals that trigger exit handlers.

/**
 * Platform-specific array of signals that can trigger exit handlers.
 * Contains signals like SIGHUP, SIGINT, SIGTERM, and others based on the platform.
 */
const signals: NodeJS.Signals[];

Usage Examples:

import { signals } from "signal-exit/signals";

console.log("Monitored signals:", signals);
// On Linux: ['SIGHUP', 'SIGINT', 'SIGTERM', 'SIGALRM', 'SIGABRT', ...]
// On Windows: ['SIGHUP', 'SIGINT', 'SIGTERM']

Internal Signal Management

Advanced functions for controlling the signal exit machinery (primarily for testing).

/**
 * Load the listeners. Likely you never need to call this, unless
 * doing a rather deep integration with signal-exit functionality.
 * Mostly exposed for the benefit of testing.
 *
 * @internal
 */
function load(): void;

/**
 * Unload the listeners. Likely you never need to call this, unless
 * doing a rather deep integration with signal-exit functionality.
 * Mostly exposed for the benefit of testing.
 *
 * @internal
 */
function unload(): void;

Browser Fallback

No-op implementations for browser environments where process signals don't exist.

/**
 * Browser-compatible version that provides the same interface
 * but performs no operations (no-op functions).
 */
const onExit: (
  cb: Handler,
  opts: { alwaysLast?: boolean }
) => () => void;

const load: () => void;
const unload: () => void;

Usage Examples:

import { onExit } from "signal-exit/browser";

// Works in browser but does nothing
const remove = onExit((code, signal) => {
  console.log("This won't be called in browser");
});

Advanced Usage Patterns

Conditional Signal Handling

import { onExit } from "signal-exit";

onExit((code, signal) => {
  if (signal) {
    console.log(`Received signal: ${signal}`);
    
    // Handle different signals differently
    switch (signal) {
      case 'SIGTERM':
        console.log("Graceful shutdown requested");
        performGracefulShutdown();
        return true; // Prevent synthetic kill
      
      case 'SIGINT':
        console.log("Interrupt signal received");
        cleanup();
        break;
      
      default:
        console.log("Other signal received");
        cleanup();
    }
  } else {
    console.log(`Process exiting with code: ${code}`);
    cleanup();
  }
});

Multiple Handlers with Ordering

import { onExit } from "signal-exit";

// This runs first
const remove1 = onExit((code, signal) => {
  console.log("First handler - emergency cleanup");
  emergencyCleanup();
});

// This runs second
const remove2 = onExit((code, signal) => {
  console.log("Second handler - regular cleanup");
  regularCleanup();
});

// This runs last (after all other handlers)
const remove3 = onExit((code, signal) => {
  console.log("Final handler - logging and reporting");
  logShutdown(code, signal);
}, { alwaysLast: true });

Handler Cleanup

import { onExit } from "signal-exit";

class Application {
  private exitHandler?: () => void;
  
  start() {
    this.exitHandler = onExit((code, signal) => {
      this.cleanup();
    });
  }
  
  stop() {
    // Remove the exit handler when no longer needed
    if (this.exitHandler) {
      this.exitHandler();
      this.exitHandler = undefined;
    }
  }
  
  cleanup() {
    console.log("Cleaning up application resources");
  }
}

Platform Compatibility

  • Node.js: Full functionality with platform-specific signal handling
  • Windows: Limited signal support (SIGHUP mapped to SIGINT)
  • Linux/macOS: Full POSIX signal support
  • Browser: Fallback module provides compatible no-op interface

Error Handling

The library is designed to be robust and handle edge cases:

  • If the global process object is unavailable, onExit returns a no-op function
  • Signal handlers are automatically cleaned up after execution
  • Multiple versions of signal-exit can coexist (backward compatibility)
  • Handlers are protected against re-execution during shutdown

Common Use Cases

  • CLI Applications: Cleanup temporary files and restore terminal state
  • Server Applications: Graceful shutdown of HTTP servers and database connections
  • Testing Frameworks: Reset global state between tests
  • Development Tools: Save unsaved work and cleanup development artifacts
  • Process Managers: Coordinate shutdown of child processes

docs

index.md

tile.json