stock-bot/libs/shutdown
2025-06-09 20:00:08 -04:00
..
src fixed reference 2025-06-07 10:41:26 -04:00
package.json fixed up lib packages to remove bun dev since they will be imported into apps 2025-06-08 14:15:04 -04:00
README.md finished shutdown lib 2025-06-07 10:40:08 -04:00
tsconfig.json trying to fix build 2025-06-09 20:00:08 -04:00

@stock-bot/shutdown

Shutdown management library for Node.js applications in the Stock Bot platform.

Features

  • Automatic Signal Handling - SIGTERM, SIGINT, SIGUSR2 (Unix), uncaught exceptions
  • Platform Support - Windows and Unix/Linux compatible
  • Multiple Callbacks - Register multiple cleanup functions
  • Timeout Protection - Configurable shutdown timeout
  • Error Handling - Failed callbacks don't block shutdown
  • TypeScript Support - Full type definitions
  • Zero Dependencies - Lightweight and efficient

Installation

bun add @stock-bot/shutdown

Quick Start

import { onShutdown, setShutdownTimeout } from '@stock-bot/shutdown';

// Configure shutdown timeout (optional, default: 30 seconds)
setShutdownTimeout(15000); // 15 seconds

// Register cleanup callbacks
onShutdown(async () => {
  console.log('Closing database connections...');
  await database.close();
});

onShutdown(async () => {
  console.log('Stopping background jobs...');
  await jobQueue.stop();
});

onShutdown(() => {
  console.log('Final cleanup...');
  // Synchronous cleanup
});

console.log('Application started. Press Ctrl+C to test graceful shutdown.');

API Reference

Convenience Functions

onShutdown(callback)

Register a cleanup callback.

onShutdown(async () => {
  await cleanup();
});

setShutdownTimeout(timeout)

Set shutdown timeout in milliseconds.

setShutdownTimeout(30000); // 30 seconds

initiateShutdown(signal?)

Manually trigger shutdown.

const result = await initiateShutdown('manual');
console.log(result.success); // true/false

shutdownAndExit(signal?, exitCode?)

Trigger shutdown and exit process.

await shutdownAndExit('manual', 0);

Advanced Usage

Manual Instance Management

import { Shutdown } from '@stock-bot/shutdown';

const shutdown = new Shutdown({
  timeout: 20000,
  autoRegister: true
});

shutdown.onShutdown(async () => {
  await cleanup();
});

// Manual shutdown
const result = await shutdown.shutdown('manual');

Configuration Options

interface ShutdownOptions {
  timeout?: number;        // Timeout in ms (default: 30000)
  autoRegister?: boolean;  // Auto-register signals (default: true)
}

Shutdown Result

interface ShutdownResult {
  success: boolean;
  callbacksExecuted: number;
  callbacksFailed: number;
  duration: number;
  error?: string;
}

Examples

Express Server

import express from 'express';
import { onShutdown, setShutdownTimeout } from '@stock-bot/shutdown';

const app = express();
const server = app.listen(3000);

setShutdownTimeout(10000);

onShutdown(async () => {
  console.log('Closing HTTP server...');
  await new Promise(resolve => server.close(resolve));
});

onShutdown(async () => {
  console.log('Closing database...');
  await database.close();
});

Worker Process

import { onShutdown } from '@stock-bot/shutdown';

let isRunning = true;

onShutdown(() => {
  console.log('Stopping worker...');
  isRunning = false;
});

// Worker loop
while (isRunning) {
  await processJob();
  await new Promise(resolve => setTimeout(resolve, 1000));
}

Signal Handling

The library automatically handles these signals:

  • SIGTERM - Termination request
  • SIGINT - Interrupt (Ctrl+C)
  • SIGUSR2 - User-defined signal (Unix only)
  • uncaughtException - Unhandled exceptions
  • unhandledRejection - Unhandled promise rejections

On Windows, only SIGTERM and SIGINT are supported due to platform limitations.

Best Practices

  1. Register callbacks early in your application startup
  2. Keep callbacks simple and focused on cleanup
  3. Use appropriate timeouts based on your cleanup needs
  4. Handle errors gracefully in callbacks
  5. Test shutdown behavior in your CI/CD pipeline

Testing

import { resetShutdown, onShutdown } from '@stock-bot/shutdown';

beforeEach(() => {
  resetShutdown(); // Clear previous state
});

test('should register shutdown callback', () => {
  let cleaned = false;
  onShutdown(() => { cleaned = true; });
  
  // Test shutdown behavior
});