fix(cron): use last_run_at as croniter base for cron jobs
compute_next_run() ignored the last_run_at parameter for cron-type schedules, always computing from _hermes_now() instead. This was inconsistent with interval jobs which DO use last_run_at as the anchor. After a crash or restart, cron jobs would compute next_run_at from the arbitrary restart time rather than the actual last execution time. While the stale detection in get_due_jobs() catches most cases, using last_run_at as the croniter base eliminates edge cases and makes the behavior consistent across schedule types. Salvaged from #9014 (authored by @beenherebefore) onto current main. The original PR branch was 2+ weeks stale and would have reverted substantial unrelated work (jobs_file_lock, workdir/context_from/ enabled_toolsets, issue #16265 state=error recovery). Kept just the 7-line substantive fix and the regression test.
This commit is contained in:
@@ -319,7 +319,14 @@ def compute_next_run(schedule: Dict[str, Any], last_run_at: Optional[str] = None
|
||||
schedule.get("expr"),
|
||||
)
|
||||
return None
|
||||
cron = croniter(schedule["expr"], now)
|
||||
# Use last_run_at as the croniter base when available, consistent
|
||||
# with interval jobs. This ensures that after a crash/restart,
|
||||
# the next run is anchored to the actual last execution time
|
||||
# rather than to an arbitrary restart time.
|
||||
base_time = now
|
||||
if last_run_at:
|
||||
base_time = _ensure_aware(datetime.fromisoformat(last_run_at))
|
||||
cron = croniter(schedule["expr"], base_time)
|
||||
next_run = cron.get_next(datetime)
|
||||
return next_run.isoformat()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user