Skip to content

[Bug]: Cron scheduler cannot detect missed executions #13947

@zhaim

Description

@zhaim

Summary

Cron scheduler has a fundamental design flaw where it cannot detect missed executions, has no execution history tracking, and returns "not-due" for manual triggers even when jobs have never run.

What went wrong?

  • cron:runs returns empty array for all jobs despite 8 being configured
  • Manual cron:run <jobId> returns {"ran": false, "reason": "not-due"} for jobs that have never executed
  • Scheduler only checks "is next run in the future?" without tracking "when did it last run?"
  • No catch-up mechanism for missed executions

Steps to reproduce

  1. Create a cron job: cron:add with daily schedule
  2. Wait 5 days without any executions
  3. Query run history: cron:runs <jobId> → returns []
  4. Attempt manual trigger: cron:run <jobId> → returns {"ok": true, "ran": false, "reason": "not-due"}
  5. Check scheduler status: cron:status → shows enabled: true

Expected behavior

  • cron:runs should show execution history
  • cron:run should have --force option for overdue jobs
  • Scheduler should detect and catch up on missed runs
  • Jobs should execute according to schedule

Actual behavior

  • 8 cron jobs created Feb 6, zero executions by Feb 11
  • All run history queries return empty
  • Manual triggers rejected with "not-due"
  • No way to force execution or recover from scheduling gaps

Environment

  • OpenClaw version: 2026.2.3 (e75e2b1)
  • OS: Ubuntu 22.04 (Linux 6.8.0-94-generic)
  • Install method: pnpm/npm

Logs

Cron job state shows only nextRunAtMs with no lastRunAtMs:

{
  "id": "ff7809e6-dfa7-4c74-b4e5-4c940c8fa4d4",
  "enabled": true,
  "schedule": {"kind": "cron", "expr": "55 23 * * *", "tz": "America/Los_Angeles"},
  "state": {"nextRunAtMs": 1770796500000}
}
cron:runs returns: {"runs": []}

cron:run returns: {"ok": true, "ran": false, "reason": "not-due"}

Proposed fix
Add execution history tracking and catch-up logic:

interface CronJobState {
  lastRunAtMs: number;      // Track last execution
  missedRuns: number;       // Detect missed executions
  consecutiveFailures: number;
  // ... existing fields
}
Add force parameter to cron:run for manual override of "not-due" jobs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingstaleMarked as stale due to inactivity

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions