Files
multi-simadmin/apps/api/src/shutdown.ts
T

38 lines
1.2 KiB
TypeScript

export interface ClosableRuntime {
close(): Promise<void>;
}
export interface SignalTarget {
once(event: 'SIGINT' | 'SIGTERM', listener: () => void): unknown;
removeListener(event: 'SIGINT' | 'SIGTERM', listener: () => void): unknown;
}
export function installBoundedShutdown(
target: SignalTarget,
runtime: ClosableRuntime,
options: { readonly timeoutMs?: number; readonly terminate?: () => void } = {},
): () => Promise<void> {
let shutdown: Promise<void> | undefined;
const timeoutMs = options.timeoutMs ?? 5_000;
const stop = (): Promise<void> => {
if (shutdown) return shutdown;
let timeout: ReturnType<typeof setTimeout> | undefined;
const deadline = new Promise<void>((resolve) => {
timeout = setTimeout(() => {
options.terminate?.();
resolve();
}, timeoutMs);
});
shutdown = Promise.race([runtime.close(), deadline]).finally(() => {
if (timeout !== undefined) clearTimeout(timeout);
target.removeListener('SIGINT', listener);
target.removeListener('SIGTERM', listener);
});
return shutdown;
};
const listener = (): void => {
void stop();
};
target.once('SIGINT', listener);
target.once('SIGTERM', listener);
return stop;
}