mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-07 02:51:50 +00:00
fix(cron): recover null next_run_at jobs and tolerate non-dict origin
Fixes #18722 get_due_jobs() now recomputes next_run_at via compute_next_run() for cron/interval jobs that arrived with null next_run_at (e.g. via direct jobs.json edits) instead of silently skipping them. _resolve_origin() guards with isinstance(origin, dict), and _deliver_result() now routes through _resolve_origin() so string/non-dict origins no longer crash the ticker. References: references #18735 (open competing fix from automated bulk PR touching 79 files); this PR is a focused single-issue contribution and adds the missing interval-recovery test variant Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
91ea3ae4b2
commit
78b635ee3c
3 changed files with 21 additions and 3 deletions
21
cron/jobs.py
21
cron/jobs.py
|
|
@ -797,19 +797,36 @@ def get_due_jobs() -> List[Dict[str, Any]]:
|
|||
|
||||
next_run = job.get("next_run_at")
|
||||
if not next_run:
|
||||
schedule = job.get("schedule", {})
|
||||
kind = schedule.get("kind")
|
||||
|
||||
# One-shot jobs use a small grace window via the dedicated helper.
|
||||
recovered_next = _recoverable_oneshot_run_at(
|
||||
job.get("schedule", {}),
|
||||
schedule,
|
||||
now,
|
||||
last_run_at=job.get("last_run_at"),
|
||||
)
|
||||
recovery_kind = "one-shot" if recovered_next else None
|
||||
|
||||
# Recurring jobs reach here only when something — typically a
|
||||
# direct jobs.json edit that bypassed add_job() — left
|
||||
# next_run_at unset. Without this branch, such jobs are
|
||||
# silently skipped forever; recompute next_run_at from the
|
||||
# schedule so they pick up at their next scheduled tick.
|
||||
if not recovered_next and kind in ("cron", "interval"):
|
||||
recovered_next = compute_next_run(schedule, now.isoformat())
|
||||
if recovered_next:
|
||||
recovery_kind = kind
|
||||
|
||||
if not recovered_next:
|
||||
continue
|
||||
|
||||
job["next_run_at"] = recovered_next
|
||||
next_run = recovered_next
|
||||
logger.info(
|
||||
"Job '%s' had no next_run_at; recovering one-shot run at %s",
|
||||
"Job '%s' had no next_run_at; recovering %s run at %s",
|
||||
job.get("name", job["id"]),
|
||||
recovery_kind,
|
||||
recovered_next,
|
||||
)
|
||||
for rj in raw_jobs:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue