// P5: the debounced DB content-flush timer, extracted from the verbatim copy // that lived in executeStreamPhase + the three sentinel summaries (4 sites). // Each site streamed deltas into a local `accumulated`/`state.accumulated` // string and threw an UPDATE at the row at most once per DB_FLUSH_INTERVAL_MS // to bound write rate under heavy streaming. // // The accumulated string stays owned by the caller (stream-phase keeps it on // the shared StreamPhaseState; the summaries keep a local) — the flusher reads // it through a `getContent` thunk at fire time, snapshotting the latest value // exactly as the inline `const snapshot = accumulated` did. No final flush is // performed on drain (matches the originals): every caller writes the full // content itself in its terminal UPDATE, so drain only cancels the pending // timer and awaits whatever write is already chained. import type { Sql } from '../../db.js'; import { DB_FLUSH_INTERVAL_MS } from './types.js'; export interface ContentFlusher { // Arm a debounced flush. No-op if one is already pending (the in-flight timer // will pick up the latest content via getContent when it fires). scheduleFlush: () => void; // Cancel any pending timer and await the in-flight write chain. Does NOT // perform a final flush — the caller's terminal UPDATE owns the final write. drain: () => Promise; } export function createContentFlusher( sql: Sql, messageId: string, getContent: () => string, intervalMs: number = DB_FLUSH_INTERVAL_MS, ): ContentFlusher { let pendingFlushTimer: NodeJS.Timeout | null = null; let flushPromise: Promise = Promise.resolve(); const flushNow = () => { if (pendingFlushTimer) { clearTimeout(pendingFlushTimer); pendingFlushTimer = null; } const snapshot = getContent(); flushPromise = flushPromise.then(() => sql`UPDATE messages SET content = ${snapshot} WHERE id = ${messageId}` ); }; const scheduleFlush = () => { if (pendingFlushTimer) return; pendingFlushTimer = setTimeout(() => { pendingFlushTimer = null; flushNow(); }, intervalMs); }; const drain = async () => { if (pendingFlushTimer) { clearTimeout(pendingFlushTimer); pendingFlushTimer = null; } await flushPromise; }; return { scheduleFlush, drain }; }