Phase 9: Faster Write-Back (CAL-15) — event-driven outbox drain #14

Merged
luckberg merged 26 commits from gsd/phase-09-faster-write-back into main 2026-06-12 21:19:17 -04:00
Showing only changes of commit 1e12d702a1 - Show all commits
+39
View File
@@ -0,0 +1,39 @@
/**
* In-process outbox drain signal (D-01 / D-03 / D-04).
*
* Module-level singleton EventEmitter — one emitter shared across all callers
* in this Node.js process. Carries a zero-payload 'drain' event: signal is
* fire-and-forget; no data crosses this boundary (D-04).
*
* Single-subscriber design:
* - signalOutboxDrain() is called only after a successful enqueue DB commit (D-01/D-03).
* - The sole listener is registered by initOutboxTrigger() in outboxWorker.ts.
* - With exactly one subscriber the default EventEmitter limit of 10 is correct.
* - Do NOT call setMaxListeners — unlike listEmitter.ts (T-04-04, 200 SSE fan-out),
* this emitter never fans out to multiple listeners.
*
* Exports: signalOutboxDrain, onOutboxDrain
*/
import { EventEmitter } from 'node:events';
// Module-level singleton — one emitter shared across all route handlers
// in this Node.js process.
const emitter = new EventEmitter();
/**
* Fire a drain signal after a successful outbox enqueue commit.
* Synchronous and fire-and-forget — never awaited (D-04).
*/
export function signalOutboxDrain(): void {
emitter.emit('drain');
}
/**
* Register a handler to be invoked on each drain signal.
* Returns an unsubscribe function; call it to stop delivery to this handler.
*/
export function onOutboxDrain(handler: () => void): () => void {
emitter.on('drain', handler);
return () => emitter.off('drain', handler);
}