/**
* Graceful shutdown handler
*/
import { Server } from 'http';
import { logger } from './logger.js';
import { config } from '../config/index.js';
import { rateLimiter } from '../middleware/rate-limiter.js';
let shutdownInProgress = false;
export function setupGracefulShutdown(server: Server): void {
const shutdown = async (signal: string) => {
if (shutdownInProgress) {
logger.warn('Shutdown already in progress', { signal });
return;
}
shutdownInProgress = true;
logger.info(`Received ${signal}, starting graceful shutdown...`);
// Stop accepting new connections
server.close(() => {
logger.info('HTTP server closed');
});
// Cleanup resources
try {
// Cleanup rate limiter
rateLimiter.destroy();
// Add other cleanup tasks here (Redis, Postgres, etc.)
logger.info('Graceful shutdown completed');
process.exit(0);
} catch (error) {
logger.error('Error during shutdown', {
error: error instanceof Error ? error.message : String(error),
});
process.exit(1);
}
// Force shutdown after timeout
setTimeout(() => {
logger.error('Forced shutdown after timeout');
process.exit(1);
}, config.shutdownTimeoutMs);
};
// Handle shutdown signals
process.on('SIGTERM', () => shutdown('SIGTERM'));
process.on('SIGINT', () => shutdown('SIGINT'));
// Handle uncaught exceptions
process.on('uncaughtException', (error) => {
logger.error('Uncaught exception', {
error: error.message,
stack: error.stack,
});
shutdown('uncaughtException');
});
// Handle unhandled rejections
process.on('unhandledRejection', (reason) => {
logger.error('Unhandled rejection', {
reason: reason instanceof Error ? reason.message : String(reason),
});
shutdown('unhandledRejection');
});
}