From 21c5f583632848d419299f4bf2d94111462c6179 Mon Sep 17 00:00:00 2001 From: Alex Gorevski Date: Tue, 17 Feb 2026 19:49:34 -0800 Subject: [PATCH] perf(cron): wrap record_run INSERT+DELETE in explicit transaction Problem: In record_run(), an INSERT into cron_runs followed by a pruning DELETE ran as separate implicit transactions. If the INSERT succeeded but the DELETE failed (e.g., due to disk pressure or lock contention), the run table would grow unboundedly since the pruning step was lost while the new row persisted. Fix: Wrap both statements in an explicit transaction using conn.unchecked_transaction(). If either statement fails, the entire transaction is rolled back, maintaining the invariant that the run history stays bounded by max_run_history. Ref: zeroclaw-labs/zeroclaw#710 (Item 5) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/cron/store.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cron/store.rs b/src/cron/store.rs index 3c27272..107e793 100644 --- a/src/cron/store.rs +++ b/src/cron/store.rs @@ -304,7 +304,12 @@ pub fn record_run( ) -> Result<()> { let bounded_output = output.map(truncate_cron_output); with_connection(config, |conn| { - conn.execute( + // Wrap INSERT + pruning DELETE in an explicit transaction so that + // if the DELETE fails, the INSERT is rolled back and the run table + // cannot grow unboundedly. + let tx = conn.unchecked_transaction()?; + + tx.execute( "INSERT INTO cron_runs (job_id, started_at, finished_at, status, output, duration_ms) VALUES (?1, ?2, ?3, ?4, ?5, ?6)", params![ @@ -319,7 +324,7 @@ pub fn record_run( .context("Failed to insert cron run")?; let keep = i64::from(config.cron.max_run_history.max(1)); - conn.execute( + tx.execute( "DELETE FROM cron_runs WHERE job_id = ?1 AND id NOT IN ( @@ -331,6 +336,8 @@ pub fn record_run( params![job_id, keep], ) .context("Failed to prune cron run history")?; + + tx.commit().context("Failed to commit cron run transaction")?; Ok(()) }) }