fix(scheduler): stop bumping updated_at in run-time writes (#420) - #425
Merged
Conversation
`update_schedule_run_times` was setting `updated_at = now()` alongside `last_run_at` / `next_run_at`. The scheduler's periodic sync loop watches `updated_at` to detect config edits — so every sync tick saw its own write from the previous `_add_job`, flagged every schedule as "updated," and re-registered all N jobs once per minute. Logs grew linearly with fleet size (~7k "Added job" lines per 8h for 13 schedules). Fix: `updated_at` now tracks config changes only. User-initiated edits (`update_schedule`, `set_schedule_enabled`) still bump it and still trigger the sync branch correctly. Runtime writes (`last_run_at` / `next_run_at`) no longer do. Applied to three call sites: - src/scheduler/database.py: update_schedule_run_times, update_process_schedule_run_times - src/backend/db/schedules.py: update_schedule_run_times Added regression tests in tests/scheduler_tests/test_sync_loop.py: - update_run_times does not mutate updated_at (agent + process) - three consecutive sync ticks with no DB edits produce zero add_job calls - a legitimate cron edit still triggers the sync update branch Closes #420 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add the "run-time writes must not bump updated_at" invariant to Flow 6 in scheduler-service.md and flag it in the update_schedule_run_times / update_process_schedule_run_times entries. This is the contract the sync loop depends on — future maintainers touching these methods need to know. Also bump the stale line ranges in those two method entries and add an entry for #420 to the feature-flows index. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add test_sync_loop.py to the Scheduler Tests category, a 2026-04-20 entry to Recent Test Additions, and bump unit-test totals by the 4 new tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
update_schedule_run_timeswas bumpingupdated_atalongside the run-time columns. The scheduler's sync loop watchesupdated_atto detect config edits, so every tick saw its own write from the previous_add_joband re-registered all N schedules once per minute — ~7k "Added job" log lines per 8h for 13 schedules, growing linearly with fleet size.updated_atis now only bumped on legitimate config changes (update_schedule,set_schedule_enabled). Runtime writes leave it alone. APScheduler idempotency (replace_existing=True) was already masking the scheduling impact, so no execution behavior changes — just DB/log churn.Changes
src/scheduler/database.py—update_schedule_run_times,update_process_schedule_run_timesno longer touchupdated_at.src/backend/db/schedules.py— same for the backend's copy ofupdate_schedule_run_times.tests/scheduler_tests/test_sync_loop.py— new regression test file (4 tests).Test Plan
pytest scheduler_tests/test_sync_loop.py -v— 4/4 passpytest scheduler_tests/— 149/149 passpytest test_schedules.py— 23/23 passdocker logs trinity-scheduler --since 5m | grep -c \"Added schedule job\"should report 0 (was ~5×N).Notes
updated_atfrom snapshot hash) to avoid a maintenance liability — Fix B would require every new schedule field (RETRY-001, VALIDATE-001, etc.) to remember to extend the hash.next_run_atis still refreshed on every_add_job/ execution completion. It wasn't gaining new information from the 60s re-writes anyway (cron is deterministic).next_run_at; unaffected — only theupdated_atbump was removed.Closes #420
Generated with Claude Code