Files
cc-platform-core/server/shutdown.js
2026-03-26 15:00:49 -04:00

72 lines
2.1 KiB
JavaScript

/**
* @cc-platform/server/shutdown — Graceful shutdown handler
*
* Extracted from both servers' SIGINT/SIGTERM handling.
* Inventory-Manager has the more thorough implementation (SIGTERM,
* unhandled rejection, uncaught exception); remoteturtle only has SIGINT.
* This module provides the comprehensive version for all services.
*
* Usage:
* const { setupGracefulShutdown } = require('@cc-platform/server/shutdown');
* setupGracefulShutdown({
* cleanup: [
* () => wsManager.close(),
* () => db.close(),
* ],
* });
*/
'use strict';
/**
* Set up graceful shutdown handlers for SIGINT, SIGTERM, and optionally
* unhandled rejections and uncaught exceptions.
*
* @param {Object} [opts={}] - Options
* @param {Function[]} [opts.cleanup=[]] - Array of cleanup functions (sync or async)
* @param {boolean} [opts.catchUnhandled=true] - Whether to handle unhandled rejections/exceptions
* @param {string} [opts.serviceName] - Service name for log messages
* @returns {{ shutdown: Function }} Object with manual shutdown trigger
*/
function setupGracefulShutdown(opts = {}) {
const cleanupFns = opts.cleanup || [];
const serviceName = opts.serviceName || 'platform';
let shuttingDown = false;
async function shutdown(signal) {
if (shuttingDown) return;
shuttingDown = true;
console.log(`\n[${serviceName}] ${signal} received, cleaning up...`);
for (const fn of cleanupFns) {
try {
await fn();
} catch (e) {
console.error(`[${serviceName}] Cleanup error:`, e.message);
}
}
console.log(`[${serviceName}] Cleanup complete`);
process.exit(0);
}
process.on('SIGINT', () => shutdown('SIGINT'));
process.on('SIGTERM', () => shutdown('SIGTERM'));
if (opts.catchUnhandled !== false) {
process.on('unhandledRejection', (reason) => {
console.error(`[${serviceName}] Unhandled rejection:`, reason);
});
process.on('uncaughtException', (err) => {
console.error(`[${serviceName}] Uncaught exception:`, err);
shutdown('uncaughtException');
});
}
return { shutdown };
}
module.exports = { setupGracefulShutdown };