#5498: Cron: honor next-heartbeat
maintainer
Cluster:
Cron Job Enhancements
## Summary
- stop requesting an immediate heartbeat for main-session jobs when wakeMode is `next-heartbeat`
- keep the existing `now` behavior: wait for `runHeartbeatOnce` when available, otherwise fall back to `requestHeartbeatNow`
- update the duplicate-timer test to assert no heartbeat poke in the `next-heartbeat` path
## Why
`next-heartbeat` is meant to queue work for the next scheduled heartbeat, but the previous implementation still poked the heartbeat immediately (sharing the same fallback path as `now` when `runHeartbeatOnce` wasn’t available). That undermined the intended delay and could contribute to duplicate timer wake-ups when multiple CronService instances are active.
## What changed
- split the `wakeMode === "now"` path from `next-heartbeat` in `executeJob`
- call `requestHeartbeatNow` only for `now` mode when `runHeartbeatOnce` is unavailable
- adjust `CronService prevents duplicate timers` test expectation accordingly
## Compromises / Risks
- `next-heartbeat` now strictly waits for the scheduled heartbeat; if a deployment disables or stalls the heartbeat, these jobs will sit queued longer than before
## Testing
- Not run (not requested)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR adjusts cron main-session wake behavior so `wakeMode: "next-heartbeat"` no longer pokes the heartbeat immediately, while keeping the existing `"now"` behavior: use `runHeartbeatOnce` when available and fall back to `requestHeartbeatNow` otherwise. It also updates the duplicate-timer regression test accordingly and switches the docs landing page logo markup to Tailwind-based dark/light images.
The changes fit into the cron subsystem by refining `executeJob`’s wake-up strategy for main-session jobs in `src/cron/service/timer.ts`, and aligning the test expectations in `src/cron/service.prevents-duplicate-timers.test.ts` to match the intended semantics of `next-heartbeat`.
<h3>Confidence Score: 3/5</h3>
- This PR is likely safe to merge, but has some behavior/coverage gaps worth double-checking.
- The cron logic change is localized and matches the stated intent, but the updated test only verifies that no heartbeat poke happens and doesn’t validate that `next-heartbeat` work is eventually processed. The docs change to root-relative asset paths could also break rendering depending on the hosting/base-path setup.
- src/cron/service/timer.ts, src/cron/service.prevents-duplicate-timers.test.ts, docs/index.md
<!-- greptile_other_comments_section -->
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#11657: fix(cron): treat skipped heartbeat as ok for one-shot jobs
by DukeDeSouth · 2026-02-08
84.4%
#12303: fix(cron): correct nextRunAtMs calculation and prevent timer stall
by colddonkey · 2026-02-09
84.3%
#8418: fix: notify user after consecutive heartbeat/cron failures
by liaosvcaf · 2026-02-04
81.4%
#12086: fix(cron): ensure timer callback fires for scheduled jobs
by divol89 · 2026-02-08
81.0%
#14667: fix: preserve missed cron runs when updating job schedule
by WalterSumbon · 2026-02-12
80.9%
#12365: test(heartbeat): don't skip empty HEARTBEAT.md for cron wake events
by tyclaudius-ai · 2026-02-09
80.9%
#12131: fix(cron): ensure timer callback fires for scheduled jobs
by divol89 · 2026-02-08
80.7%
#12122: fix(cron): ensure timer callback fires for scheduled jobs
by divol89 · 2026-02-08
80.6%
#10120: fix(cron): ensure next run is strictly in the future (#10035)
by zenchantlive · 2026-02-06
80.4%
#11813: fix(cron): ensure 'at' schedule type correctly registers nextWakeAt...
by leo-reifying · 2026-02-08
80.3%