{{ message }}
fix: tolerate late heartbeats so drifting timers don't skip executions#534
Merged
Conversation
Long setTimeout delays drift (OS sleep, GC, throttling, clock skew). On daily/weekly schedules a heartbeat could wake a few seconds late, fail the exact-second match, skip the execution and emit a spurious "missed execution" warning. The miss rate scaled with timer duration, so daily/weekly jobs were hit hardest (reported in #485, and the WSL2 clock-drift reports in #475). Introduce a configurable `missedExecutionTolerance` (ms, default 1000): a heartbeat that wakes within the tolerance of the slot it was armed for runs that slot instead of reporting it missed. The tolerance is always bounded by the gap to the next slot, so a late run can never bleed into the following one and a tolerance larger than the interval can never run a slot twice. The run/miss/wait decision is extracted into a pure `planBeat` function with exhaustive scenario tests; the runner now drives off the slot it armed for rather than re-matching the (late) wall clock.
This was referenced Jun 16, 2026
Merged
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.

Closes #485
Problem
Long
setTimeoutdelays drift (OS sleep, GC, throttling, clock skew). On daily/weekly schedules a heartbeat could wake a few seconds late, fail the exact-secondmatch(), skip the execution and emit a spuriousmissed executionwarning. The miss rate scaled with timer duration, so daily/weekly jobs were hit hardest.Reported in #485 (with a strong inspector-level diagnosis showing the timer fires but the callback is skipped, miss rate correlating with timer duration) and the WSL2 clock-drift reports in #475.
Fix
New configurable option
missedExecutionTolerance(ms, default 1000): a heartbeat that wakes within the tolerance of the slot it was armed for runs that slot instead of reporting it missed.The tolerance is always bounded by the gap to the next slot, so:
The run / miss / wait decision is extracted into a pure
planBeatfunction with exhaustive scenario tests (on-time, late-within-tolerance, late-beyond-tolerance, early fire, the 1s-cron cap, hourly recovery, the superseded-slot boundary, long-block catch-up). The runner now drives off the slot it armed for rather than re-matching the late wall clock.The existing "missed execution" suppression (
suppressMissedWarningand the auto-suppress when anexecution:missedlistener is attached) is unchanged.Notes for #475 (WSL2)
That one is environmental: the WSL2 guest clock desyncs from the Windows host (microsoft/WSL#10006). The grace window softens minor drift, but a large clock jump is still a genuine miss. The confirmed user fix is an NTP/
hwclockresync.