UNPKG

@upstash/context7-mcp

Version:
64 lines (63 loc) • 2.08 kB
const DEFAULT_CLOSE_TIMEOUT_MS = 5_000; const DEFAULT_FLUSH_TIMEOUT_MS = 5_000; async function withTimeout(operation, timeoutMs, description) { let timeout; try { await Promise.race([ operation(), new Promise((_resolve, reject) => { timeout = setTimeout(() => reject(new Error(`${description} exceeded ${timeoutMs}ms`)), timeoutMs); }), ]); } finally { if (timeout) clearTimeout(timeout); } } /** * Coordinates one bounded, idempotent process shutdown for HTTP and stdio. * Passing an input lifecycle additionally treats stdio EOF as termination. */ export function installProcessShutdown(handle, options = {}) { const signals = options.signals ?? process; const exit = options.exit ?? ((code) => process.exit(code)); const closeTimeoutMs = options.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS; const flushTimeoutMs = options.flushTimeoutMs ?? DEFAULT_FLUSH_TIMEOUT_MS; let shutdownPromise; const reportError = (error) => { try { options.onerror?.(error); } catch { // A reporting callback must not prevent shutdown. } }; const shutdown = () => { shutdownPromise ??= (async () => { let exitCode = 0; try { await withTimeout(() => handle.close(), closeTimeoutMs, "Server close"); } catch (error) { exitCode = 1; reportError(error); } try { if (options.flush) { await withTimeout(options.flush, flushTimeoutMs, "OpenTelemetry flush"); } } catch (error) { reportError(error); } exit(exitCode); })(); }; options.input?.once("end", shutdown); options.input?.once("close", shutdown); signals.once("SIGHUP", shutdown); signals.once("SIGINT", shutdown); signals.once("SIGTERM", shutdown); return shutdown; }