UNPKG

@travetto/runtime

Version:

Runtime for travetto applications.

69 lines (60 loc) 2.13 kB
import { Env } from './env.ts'; import { Util } from './util.ts'; import { TimeUtil } from './time.ts'; /** * Shutdown manager, allowing for listening for graceful shutdowns */ export class ShutdownManager { static #registered = false; static #handlers: { name?: string, handler: () => (void | Promise<void>) }[] = []; /** * On Shutdown requested * @param name name to log for * @param handler synchronous or asynchronous handler */ static onGracefulShutdown(handler: () => (void | Promise<void>), name?: string | { constructor: Function }): () => void { if (!this.#registered) { this.#registered = true; const done = (): void => { this.gracefulShutdown(0); }; process.on('SIGUSR2', done).on('SIGTERM', done).on('SIGINT', done); } this.#handlers.push({ handler, name: typeof name === 'string' ? name : name?.constructor?.Ⲑid }); return () => { const idx = this.#handlers.findIndex(x => x.handler === handler); if (idx >= 0) { this.#handlers.splice(idx, 1); } }; } /** * Wait for graceful shutdown to run and complete */ static async gracefulShutdown(code: number | string | undefined = process.exitCode): Promise<void> { await Util.queueMacroTask(); // Force the event loop to wait one cycle if (code !== undefined) { process.exitCode = code; } if (this.#handlers.length) { console.debug('Graceful shutdown: started'); const items = this.#handlers.splice(0, this.#handlers.length); const handlers = Promise.all(items.map(async ({ name, handler }) => { if (name) { console.debug('Stopping', { name }); } try { return await handler(); } catch (err) { console.error('Error shutting down', { name, err }); } })); await Promise.race([ Util.nonBlockingTimeout(TimeUtil.fromValue(Env.TRV_SHUTDOWN_WAIT.val) ?? 2000), // Wait 2s and then force finish handlers, ]); console.debug('Graceful shutdown: completed'); } if (code !== undefined) { process.exit(); } } }