Skip to content

fix(cron): prevent spin loop when job completes within firing second#17967

Merged
steipete merged 2 commits intoopenclaw:mainfrom
Operative-001:fix/cron-spin-loop-17821
Feb 16, 2026
Merged

fix(cron): prevent spin loop when job completes within firing second#17967
steipete merged 2 commits intoopenclaw:mainfrom
Operative-001:fix/cron-spin-loop-17821

Conversation

@Operative-001
Copy link
Copy Markdown
Contributor

@Operative-001 Operative-001 commented Feb 16, 2026

Fixes #17821

Problem

When a cron job fires at 13:00:00.014 and completes at 13:00:00.021, computeNextRunAtMs was flooring nowMs to 13:00:00.000 and asking croner for the next occurrence from that exact boundary. Croner could return 13:00:00.000 (same second) since it uses >= semantics, causing the job to be immediately re-triggered hundreds of times per second.

Solution

Ask croner for the next occurrence starting from the NEXT second (e.g., 13:00:01.000). This ensures we always skip the current/elapsed second and correctly return the next day's occurrence.

This also correctly handles the before-match case: if nowMs is 11:59:59.500, we ask from 12:00:00.000, and croner returns today's 12:00:00.000 match.

Testing

  • Added regression tests for the spin loop scenario
  • Existing tests continue to pass (all edge cases for "before match", "at match", "mid-second", etc.)

Greptile Summary

Fixed critical spin loop bug where cron jobs that fired and completed within the same second would immediately retrigger hundreds of times per second.

Key Changes

  • Changed computeNextRunAtMs to ask croner for the next occurrence starting from the NEXT second (current second + 1000ms) instead of the current second
  • Removed the nextMs > nowSecondMs safety check since asking from the next second already guarantees the result is in the future
  • Added comprehensive regression tests covering jobs completing at various millisecond offsets within their firing second

How It Works
The old code floored nowMs to the current second boundary and asked croner from that point. Due to croner's >= semantics, it would return the current second if it matched the schedule. The code then filtered this out with nextMs > nowSecondMs, which caused it to return undefined. When nextRunAtMs is undefined, the job is immediately considered "due" on the next tick, creating a spin loop.

The fix ensures croner is always asked from at least 1 second in the future, so it never returns the current/elapsed second. This prevents the undefined return value and correctly schedules the job for the next valid occurrence (e.g., next day for daily jobs).

Confidence Score: 5/5

  • This PR is safe to merge with no risk
  • The fix is minimal, well-tested, and directly addresses the root cause. The logic change is sound (asking from next second instead of current second), comprehensive regression tests were added for the exact failure scenario, existing tests continue to pass, and the implementation correctly handles all edge cases including sub-second timing and the "before match" case.
  • No files require special attention

Last reviewed commit: 4dd449c

(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!

…penclaw#17821)

When a cron job fires at 13:00:00.014 and completes at 13:00:00.021,
computeNextRunAtMs was flooring nowMs to 13:00:00.000 and asking croner
for the next occurrence from that exact boundary. Croner could return
13:00:00.000 (same second) since it uses >= semantics, causing the job
to be immediately re-triggered hundreds of times.

Fix: Ask croner for the next occurrence starting from the NEXT second
(e.g., 13:00:01.000). This ensures we always skip the current/elapsed
second and correctly return the next day's occurrence.

This also correctly handles the before-match case: if nowMs is
11:59:59.500, we ask from 12:00:00.000, and croner returns today's
12:00:00.000 match.

Added regression tests for the spin loop scenario.
@steipete steipete merged commit de6cc05 into openclaw:main Feb 16, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Cron Job Spin Loop Bug Report

2 participants