@kadi.build/local-remote-file-manager-ability
Version:
Local & Remote File Management System with S3-compatible container registry, HTTP server provider, file streaming, and comprehensive testing suite
160 lines (132 loc) โข 4.52 kB
JavaScript
// Process Management Utility
class ProcessManager {
constructor() {
this.cleanupHandlers = new Set();
this.isShuttingDown = false;
this.shutdownTimer = null;
this.forceExitTimer = null;
this.setupSignalHandlers();
}
setupSignalHandlers() {
// Handle various termination signals
const signals = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
signals.forEach(signal => {
process.on(signal, () => {
console.log(`\n๐ Received ${signal}, initiating graceful shutdown...`);
this.gracefulShutdown(`${signal} signal`);
});
});
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
console.error('๐ฅ Uncaught Exception:', error);
this.forceShutdown('uncaught exception');
});
// Handle unhandled promise rejections
process.on('unhandledRejection', (reason, promise) => {
console.error('๐ฅ Unhandled Rejection at:', promise, 'reason:', reason);
this.forceShutdown('unhandled rejection');
});
}
// Register a cleanup handler
registerCleanupHandler(handler, description = 'cleanup') {
if (typeof handler !== 'function') {
throw new Error('Cleanup handler must be a function');
}
const cleanupItem = { handler, description };
this.cleanupHandlers.add(cleanupItem);
// Return a function to unregister the handler
return () => this.cleanupHandlers.delete(cleanupItem);
}
// Set up automatic shutdown after delay
scheduleAutoShutdown(delaySeconds, reason = 'auto-shutdown timer') {
if (this.shutdownTimer) {
clearTimeout(this.shutdownTimer);
}
if (delaySeconds > 0) {
console.log(`โฐ Auto-shutdown scheduled in ${delaySeconds} seconds`);
this.shutdownTimer = setTimeout(() => {
this.gracefulShutdown(reason);
}, delaySeconds * 1000);
}
}
// Cancel automatic shutdown
cancelAutoShutdown() {
if (this.shutdownTimer) {
clearTimeout(this.shutdownTimer);
this.shutdownTimer = null;
console.log('โฐ Auto-shutdown cancelled');
}
}
// Perform graceful shutdown
async gracefulShutdown(reason = 'shutdown', forceExitAfter = 10000) {
if (this.isShuttingDown) {
console.log('๐ Shutdown already in progress...');
return;
}
this.isShuttingDown = true;
console.log(`๐ Starting graceful shutdown (${reason})...`);
// Set up force exit timer as safety net
this.forceExitTimer = setTimeout(() => {
console.log('โ ๏ธ Force exit after timeout');
process.exit(1);
}, forceExitAfter);
try {
// Cancel any pending auto-shutdown
this.cancelAutoShutdown();
// Run cleanup handlers in reverse order (LIFO)
const handlers = Array.from(this.cleanupHandlers).reverse();
for (const { handler, description } of handlers) {
try {
console.log(` ๐งน Running ${description}...`);
await handler();
} catch (error) {
console.warn(` โ ๏ธ ${description} failed: ${error.message}`);
}
}
console.log('โ
Graceful shutdown completed');
} catch (error) {
console.error('โ Error during shutdown:', error.message);
} finally {
// Clear force exit timer
if (this.forceExitTimer) {
clearTimeout(this.forceExitTimer);
}
process.exit(0);
}
}
// Force immediate shutdown
forceShutdown(reason = 'force') {
console.log(`๐ฅ Force shutdown (${reason})`);
process.exit(1);
}
// Keep process alive until shutdown
keepAlive() {
return new Promise(() => { }); // Infinite promise
}
// Keep alive with periodic heartbeat
keepAliveWithHeartbeat(intervalSeconds = 60, onHeartbeat = null) {
const heartbeatInterval = setInterval(() => {
if (this.isShuttingDown) {
clearInterval(heartbeatInterval);
return;
}
if (onHeartbeat) {
try {
onHeartbeat();
} catch (error) {
console.warn('โ ๏ธ Heartbeat callback error:', error.message);
}
} else {
console.log(`๐ Process heartbeat - ${new Date().toLocaleTimeString()}`);
}
}, intervalSeconds * 1000);
// Register cleanup to stop heartbeat
this.registerCleanupHandler(() => {
clearInterval(heartbeatInterval);
}, 'heartbeat cleanup');
return this.keepAlive();
}
}
// Singleton instance
const processManager = new ProcessManager();
export { ProcessManager, processManager };