improved logger and added shutdown handler
This commit is contained in:
parent
7c2e055dd4
commit
83e8c44d98
4 changed files with 123 additions and 2 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Data Service - Combined live and historical data ingestion
|
* Data Service - Combined live and historical data ingestion
|
||||||
*/
|
*/
|
||||||
import { createLogger } from '@stock-bot/logger';
|
import { createLogger, GracefulShutdownManager } from '@stock-bot/logger';
|
||||||
import { loadEnvVariables } from '@stock-bot/config';
|
import { loadEnvVariables } from '@stock-bot/config';
|
||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { serve } from '@hono/node-server';
|
import { serve } from '@hono/node-server';
|
||||||
|
|
@ -11,6 +11,8 @@ loadEnvVariables();
|
||||||
|
|
||||||
const app = new Hono();
|
const app = new Hono();
|
||||||
const logger = createLogger('data-service');
|
const logger = createLogger('data-service');
|
||||||
|
const shutdownManager = new GracefulShutdownManager(logger);
|
||||||
|
|
||||||
const PORT = parseInt(process.env.DATA_SERVICE_PORT || '3002');
|
const PORT = parseInt(process.env.DATA_SERVICE_PORT || '3002');
|
||||||
// Health check endpoint
|
// Health check endpoint
|
||||||
app.get('/health', (c) => {
|
app.get('/health', (c) => {
|
||||||
|
|
|
||||||
116
libs/logger/src/gracefulShutdown.ts
Normal file
116
libs/logger/src/gracefulShutdown.ts
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
import pino from 'pino';
|
||||||
|
|
||||||
|
interface ShutdownHandler {
|
||||||
|
name: string;
|
||||||
|
handler: () => Promise<void> | void;
|
||||||
|
timeout?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GracefulShutdownManager {
|
||||||
|
private logger: pino.Logger;
|
||||||
|
private handlers: ShutdownHandler[] = [];
|
||||||
|
private isShuttingDown = false;
|
||||||
|
private startTime = Date.now();
|
||||||
|
|
||||||
|
constructor(logger: pino.Logger) {
|
||||||
|
this.logger = logger;
|
||||||
|
this.setupSignalHandlers();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a shutdown handler
|
||||||
|
*/
|
||||||
|
addHandler(handler: ShutdownHandler): void {
|
||||||
|
this.handlers.push(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup signal handlers for graceful shutdown
|
||||||
|
*/
|
||||||
|
private setupSignalHandlers(): void {
|
||||||
|
// Graceful shutdown signals
|
||||||
|
process.on('SIGTERM', () => this.shutdown('SIGTERM', 0));
|
||||||
|
process.on('SIGINT', () => this.shutdown('SIGINT', 0));
|
||||||
|
process.on('SIGUSR2', () => this.shutdown('SIGUSR2', 0)); // nodemon
|
||||||
|
|
||||||
|
// Fatal error handlers
|
||||||
|
process.on('uncaughtException', (error) => {
|
||||||
|
this.logger.error('Uncaught exception', error, { fatal: true });
|
||||||
|
this.shutdown('uncaughtException', 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
process.on('unhandledRejection', (reason, promise) => {
|
||||||
|
this.logger.error('Unhandled promise rejection', {
|
||||||
|
reason: reason instanceof Error ? reason.message : reason,
|
||||||
|
stack: reason instanceof Error ? reason.stack : undefined,
|
||||||
|
fatal: true
|
||||||
|
});
|
||||||
|
this.shutdown('unhandledRejection', 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Process warnings
|
||||||
|
process.on('warning', (warning) => {
|
||||||
|
this.logger.warn('Process warning', {
|
||||||
|
name: warning.name,
|
||||||
|
message: warning.message,
|
||||||
|
stack: warning.stack
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Final exit
|
||||||
|
process.on('exit', (code) => {
|
||||||
|
const uptime = Date.now() - this.startTime;
|
||||||
|
console.log(`Process exiting with code ${code} after ${uptime}ms`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute graceful shutdown
|
||||||
|
*/
|
||||||
|
private async shutdown(signal: string, exitCode: number): Promise<void> {
|
||||||
|
if (this.isShuttingDown) {
|
||||||
|
this.logger.warn('Force shutdown - multiple signals received');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isShuttingDown = true;
|
||||||
|
const shutdownStart = Date.now();
|
||||||
|
|
||||||
|
this.logger.info('Graceful shutdown initiated', {
|
||||||
|
signal,
|
||||||
|
exitCode,
|
||||||
|
uptime: Date.now() - this.startTime,
|
||||||
|
memoryUsage: process.memoryUsage(),
|
||||||
|
handlersCount: this.handlers.length
|
||||||
|
});
|
||||||
|
|
||||||
|
// Execute shutdown handlers
|
||||||
|
for (const handler of this.handlers) {
|
||||||
|
try {
|
||||||
|
this.logger.info(`Executing shutdown handler: ${handler.name}`);
|
||||||
|
const timeout = handler.timeout || 5000;
|
||||||
|
|
||||||
|
await Promise.race([
|
||||||
|
Promise.resolve(handler.handler()),
|
||||||
|
new Promise((_, reject) =>
|
||||||
|
setTimeout(() => reject(new Error(`Timeout after ${timeout}ms`)), timeout)
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
this.logger.info(`Shutdown handler completed: ${handler.name}`);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(`Shutdown handler failed: ${handler.name}`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const shutdownDuration = Date.now() - shutdownStart;
|
||||||
|
this.logger.info('Graceful shutdown completed', {
|
||||||
|
signal,
|
||||||
|
shutdownDuration,
|
||||||
|
totalUptime: Date.now() - this.startTime
|
||||||
|
});
|
||||||
|
|
||||||
|
// Give logs time to flush
|
||||||
|
setTimeout(() => process.exit(exitCode), 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -45,3 +45,5 @@ export type {
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
export type { LoggingMiddlewareOptions } from './middleware';
|
export type { LoggingMiddlewareOptions } from './middleware';
|
||||||
|
|
||||||
|
export { GracefulShutdownManager } from './gracefulShutdown';
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,6 @@
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/*"
|
"src/**/*"
|
||||||
], "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
|
],
|
||||||
|
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"],
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue