From aa42fccbd45a2f283b808e44d78f754407cc5be4 Mon Sep 17 00:00:00 2001 From: philipp Date: Sat, 6 Jun 2026 15:55:41 +0200 Subject: [PATCH] Run quote lifecycle retention on a timer Proof: History writer now runs quote lifecycle retention immediately and on a repo-owned timer independent of Kafka batch traffic, with regression coverage for the timer and shutdown cleanup. Assumptions: A one-minute maintenance cadence remains the approved bounded retention cadence for this turn. Still fake: Retention remains aggregate rollup evidence for pruned non-success detail; already-pruned historical detail cannot be reconstructed. --- src/apps/history-writer.mjs | 7 +++++++ test/history-writer-static.test.mjs | 3 +++ 2 files changed, 10 insertions(+) diff --git a/src/apps/history-writer.mjs b/src/apps/history-writer.mjs index 263674f..f7c8764 100644 --- a/src/apps/history-writer.mjs +++ b/src/apps/history-writer.mjs @@ -229,6 +229,12 @@ await refreshQuoteLifecycleRetentionState().catch((error) => { state.retention_error = serializeError(error); }); +const quoteLifecycleRetentionMaintenanceTimer = setInterval(() => { + void maybeRunQuoteLifecycleRetentionMaintenance(); +}, quoteLifecycleRetentionMaintenanceIntervalMs); +quoteLifecycleRetentionMaintenanceTimer.unref?.(); +await maybeRunQuoteLifecycleRetentionMaintenance({ force: true }); + for (const historyConsumer of durableConsumers) { await runHistoryConsumer(historyConsumer); } @@ -770,6 +776,7 @@ function resumeConsumers() { } async function shutdown() { + clearInterval(quoteLifecycleRetentionMaintenanceTimer); await controlApi.close().catch(() => {}); await Promise.allSettled([ ...durableConsumers.map((historyConsumer) => historyConsumer.disconnect()), diff --git a/test/history-writer-static.test.mjs b/test/history-writer-static.test.mjs index 43a86ad..7efdbef 100644 --- a/test/history-writer-static.test.mjs +++ b/test/history-writer-static.test.mjs @@ -24,6 +24,9 @@ test('history writer replays durable topics but joins the raw quote firehose liv assert.match(source, /runQuoteLifecycleRetentionMaintenance/); assert.match(source, /loadQuoteLifecycleRetentionSummary/); assert.match(source, /maybeRunQuoteLifecycleRetentionMaintenance/); + assert.match(source, /quoteLifecycleRetentionMaintenanceTimer\s*=\s*setInterval/); + assert.match(source, /maybeRunQuoteLifecycleRetentionMaintenance\(\{\s*force:\s*true\s*\}\)/); + assert.match(source, /clearInterval\(quoteLifecycleRetentionMaintenanceTimer\)/); assert.match(source, /retention_mode/); assert.match(source, /storage_pressure/); assert.doesNotMatch(source, /RetainRecentMs/);