/** Max time allowed for plugin host cleanup hooks before failing shutdown. */ const PLUGIN_HOST_CLEANUP_TIMEOUT_MS = 5_000; /** Error raised when a plugin host cleanup hook exceeds the shutdown timeout. */ class PluginHostCleanupTimeoutError extends Error { constructor(hookId: string) { super(`plugin host cleanup timed out: ${hookId}`); this.name = "PluginHostCleanupTimeoutError"; } } /** Runs plugin host cleanup with a bounded timeout and clears the timer afterward. */ export async function withPluginHostCleanupTimeout( hookId: string, cleanup: () => T | Promise, ): Promise { let timeout: NodeJS.Timeout | undefined; try { return await Promise.race([ Promise.resolve().then(cleanup), new Promise((_, reject) => { timeout = setTimeout(() => { reject(new PluginHostCleanupTimeoutError(hookId)); }, PLUGIN_HOST_CLEANUP_TIMEOUT_MS); timeout.unref?.(); }), ]); } finally { if (timeout) { clearTimeout(timeout); } } }