/** * detach/flush.ts — Drain every in-flight detached handle to terminal. * * Pattern: Drain-loop with deadline. Same shape as a graceful HTTP * server shutdown: snapshot the queue, await everything in * flight, repeat until empty or deadline. * Role: Graceful-shutdown hook for consumers who launched * fire-and-forget work and want to make sure it actually * flushed before exiting (server stop, test cleanup, etc.). * * Why iterate (not single Promise.all over a snapshot): * - A child stage can itself call `detachAndForget` while running — * new handles arrive WHILE we're flushing. A single snapshot would * miss them. Looping until `size() === 0` drains transitively. * * Why dedupe via `seen` Set: * - Handles already terminal (but not yet `unregister`ed by their * driver's finally-block) can re-appear in subsequent snapshots. * Without dedupe, the `done` counter would double-count them. * * Why `Promise.allSettled` (not `Promise.all`): * - One handle's rejection must NOT abort the rest. A failed child * is normal (it's why `wait()` rejects); we still want to drain * the siblings. */ export interface FlushResult { /** Handles whose `wait()` we EXPLICITLY awaited and saw fulfilled. * Best-effort count — a child that completes inside another's * `wait()` may finish (and unregister) before we get a chance to * await it directly. The DRAIN is still guaranteed (registry empty * on return); only the COUNT is approximate. */ readonly done: number; /** Handles whose `wait()` rejected. Same best-effort semantics. */ readonly failed: number; /** Handles still in-flight when the deadline expired. `0` indicates * a successful (complete) drain — registry was empty on return. */ readonly pending: number; } export interface FlushOptions { /** Max wall-clock to spend draining, in milliseconds. Default 30s. */ readonly timeoutMs?: number; } /** * Wait for every in-flight detached handle to reach a terminal state. * Returns counts for diagnostics. PROCESS-WIDE — drains every driver * across every executor. For per-executor scoping, consumers should * collect their own handles from `executor.detachAndJoinLater(...)` * calls and await `Promise.allSettled([...].map(h => h.wait()))` * themselves. * * @example Graceful server shutdown * ```typescript * import { flushAllDetached } from 'footprintjs/detach'; * * process.on('SIGTERM', async () => { * const stats = await flushAllDetached({ timeoutMs: 10_000 }); * console.log(`Drained ${stats.done} done, ${stats.failed} failed, ${stats.pending} pending.`); * process.exit(stats.pending === 0 ? 0 : 1); * }); * ``` */ export declare function flushAllDetached(opts?: FlushOptions): Promise;