← Back to PRs

#12086: fix(cron): ensure timer callback fires for scheduled jobs

by divol89 open 2026-02-08 20:52 View on GitHub →
channel: signal channel: telegram app: web-ui gateway cli agents stale
## Description Fixes #12081: Cron scheduler setTimeout callback never fires despite cronEnabled=true and nextWakeAtMs being set. ### Root Cause The `armTimer` function had a bug where it would unconditionally set `state.timer = null` before checking if a new timer should be created: ```typescript if (state.timer) { clearTimeout(state.timer); } state.timer = null; // <-- THIS HAPPENS ALWAYS if (!state.deps.cronEnabled) { return; // timer stays null! } const nextAt = nextWakeAtMs(state); if (!nextAt) { return; // timer stays null! } ``` If `cronEnabled` was false or `nextWakeAtMs` returned undefined, the timer would be cleared and set to null, but no new timer would be created. ### Changes 1. **Fixed timer clearing logic**: Only clear existing timer when we're about to create a new one 2. **Removed `unref()`**: The timer should keep the event loop alive for scheduled cron jobs 3. **Added debug logging**: Log timer arming details and callback invocation for easier diagnosis ### Testing The fix ensures that: - When cron is disabled, existing timers are properly cleared - When no jobs are due (`nextWakeAtMs` returns undefined), timers are cleared - When jobs are due, a new timer is always created - Timer callback will fire at scheduled time - Event loop stays alive for scheduled jobs ### Checklist - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update **Wallet: BYCgQQpJTJT1odaunfvk6gtm5hVd7Xu93vYwbumFfqgHb3** <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR fixes cron scheduling/timer arming so scheduled jobs reliably keep a timer alive and the callback executes, and adjusts cron store loading to allow skipping `recomputeNextRuns` during timer ticks. It also includes a few unrelated QoL changes across config (optional model provider baseUrl + defaults), messaging integrations (Signal edits, Telegram command reset, sender id handling), TTS (OpenAI baseUrl support), and UI markdown performance tweaks. Key risk areas are concentrated around timer lifecycle/state management and edit-message parsing semantics; the other changes are mostly additive but should be double-checked for consistency with existing expectations. <h3>Confidence Score: 3/5</h3> - This PR is reasonably safe to merge after a few correctness/consistency fixes. - The core cron timer fix is straightforward, but there are a couple of concrete issues introduced (timer state not nulled after clearing; inconsistent edit detection when target timestamp is non-numeric; unused constant in UI markdown after changing thresholds). Addressing these should reduce behavioral ambiguity and avoid build failures in stricter TS/lint configs. - src/cron/service/timer.ts, src/signal/monitor/event-handler.ts, ui/src/ui/markdown.ts <!-- greptile_other_comments_section --> <!-- /greptile_comment -->

Most Similar PRs