#19484: Fix cron store backup churn
size: S
Cluster:
Cron Job Fixes
## Summary
`saveCronStore` in `src/cron/store.ts` was always writing `jobs.json.bak` on every save, even when the serialized cron payload was unchanged. This created unnecessary disk churn and made the backup file less useful because it was being overwritten with the latest state each write.
## Root Cause
The previous save flow always:
1. wrote a temp file,
2. renamed it over `jobs.json`,
3. copied the new `jobs.json` to `jobs.json.bak`.
That means `.bak` represented the newest snapshot, not the previous one, and it was rewritten on every persist tick.
## Fix
- Added a pre-write read of the current store content.
- Added a no-op short-circuit when serialized JSON is unchanged.
- When content changes, create `jobs.json.bak` from the previous on-disk `jobs.json` before replacing it.
This preserves meaningful backup semantics and avoids unnecessary backup rewrites.
## Tests
Added/updated tests in `src/cron/store.test.ts`:
- verifies no backup file is created when saving identical content twice,
- verifies backup contains the previous store content after a changed save.
## Validation
- `pnpm lint`
- `pnpm build`
- `pnpm test`
## AI Assistance
- [x] AI-assisted
- [x] Fully tested
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixed unnecessary disk churn in cron store backup mechanism. The previous implementation always created a backup file on every save, even when the content was unchanged. Now the function reads the current file first, short-circuits if the serialized JSON is identical, and only creates `jobs.json.bak` from the previous `jobs.json` when the content actually changes. This preserves proper backup semantics (backup = previous state, not current state) and eliminates wasteful disk writes.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The implementation is well-designed with proper error handling, atomic file operations via temp files, and comprehensive test coverage. The logic correctly handles all edge cases including missing files, unchanged content, and first-time saves. The changes eliminate unnecessary disk I/O while preserving backup semantics.
- No files require special attention
<sub>Last reviewed commit: 3dbb196</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#6827: fix: cron scheduler cleanup orphaned .tmp files on startup
by fatelei · 2026-02-02
78.3%
#16932: fix(cron): retry rename on EBUSY and fall back to copyFile on Windows
by zerone0x · 2026-02-15
77.9%
#8744: fix(cron): load persisted cron jobs on gateway startup
by revenuestack · 2026-02-04
76.6%
#9393: fix(cron): avoid recomputeNextRuns on forceReload
by matthewpapa07 · 2026-02-05
76.5%
#18144: fix(cron): clear stuck runningAtMs after timeout and add maintenanc...
by taw0002 · 2026-02-16
75.1%
#14667: fix: preserve missed cron runs when updating job schedule
by WalterSumbon · 2026-02-12
74.8%
#17064: fix(cron): prevent control-plane starvation during startup catch-up...
by donggyu9208 · 2026-02-15
74.8%
#19372: fix(cron): normalize jobId → id for file-backed jobs
by namabile · 2026-02-17
74.7%
#8698: fix(cron): default enabled to true for new jobs
by emmick4 · 2026-02-04
74.6%
#12368: fix(cron): respect OPENCLAW_STATE_DIR for cron store path
by ComBba · 2026-02-09
74.5%