openclaw - ✅(Solved) Fix Cron job runs repeatedly after manual trigger via cron run [1 pull requests, 3 comments, 3 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#52097Fetched 2026-04-08 01:15:39
View on GitHub
Comments
3
Participants
3
Timeline
8
Reactions
0
Author
Timeline (top)
referenced ×4commented ×3cross-referenced ×1

Fix Action

Fixed

PR fix notes

PR #52109: fix(cron): apply MIN_REFIRE_GAP_MS to every-schedule jobs

Description (problem / solution / changelog)

Summary

  • Problem: Every-schedule cron jobs did not enforce MIN_REFIRE_GAP_MS (2s) after execution. When job execution time exceeded the interval (e.g. a 5s-interval job taking 10–17s), the anchor-based next-run computation landed at or before endedAt, making the job immediately due again — creating a tight refire loop.
  • Why it matters: Users with short-interval every jobs (or jobs whose execution time exceeds the interval) experience runaway repeated execution, wasting resources and flooding logs.
  • What changed: Removed the if (cron) / else branch in applyJobResult so MIN_REFIRE_GAP_MS applies to all schedule kinds uniformly — same safety net that cron-schedule jobs already had.
  • What did NOT change: The MIN_REFIRE_GAP_MS value (2s), cron-schedule behavior, error-backoff logic, armTimer floor delay, or any other scheduling paths.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #52097

User-visible / Behavior Changes

Every-schedule cron jobs now enforce a minimum 2-second gap between the end of one execution and the start of the next. This prevents tight refire loops when execution time exceeds the scheduled interval. Normal intervals (where execution finishes well before the next scheduled time) are unaffected.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: Ubuntu 24.04 (Docker, 32-core server)
  • Runtime/container: OpenClaw v2026.3.14 in Docker
  • Model/provider: N/A (systemEvent payload, no model invocation)
  • Integration/channel: N/A
  • Relevant config: schedule: { kind: "every", everyMs: 5000 }

Steps

  1. Create an every 5s cron job: openclaw cron add --name "bug-test" --every 5s --session main --system-event "tick"
  2. Wait for the job to fire naturally (~5s)
  3. After execution completes, check nextRunAtMs relative to now

Expected

nextRunAtMs should be at least 2 seconds after endedAt (the MIN_REFIRE_GAP_MS safety net), preventing immediate re-firing.

Actual (before fix)

nextRunAtMs equaled endedAt exactly (nextRun-now: 0 sec), causing the job to fire again immediately in a tight loop.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Unit tests: Two regression tests added in src/cron/service/timer.applyJobResult-schedule-catch.test.ts:

  1. Daily-interval job where lastRunAtMs + everyMs lands exactly at endedAt
  2. Short-interval (5s) job where execution (10s) exceeds the interval

Both tests fail without the fix (asserting nextRunAtMs > endedAt + 1999) and pass with it.

Live verification on a running OpenClaw gateway (Docker):

We reproduced the bug and verified the fix on a live OpenClaw deployment ("Bramble") running in Docker on a remote server:

  1. Bug reproduction (before fix): Created an every 5s job on the live gateway running openclaw:deploy. The job took 17s to execute. After execution, nextRunAtMs was exactly equal to endedAtnextRun-now: 0 sec. The job was in a tight refire loop, executing back-to-back every ~17s instead of respecting the 5s interval.

  2. Fix deployment: Cherry-picked the one-line fix onto the running branch (fix/slack-runtime-api-docker-imports), built a new Docker image (openclaw:refire-fix), and deployed it to the same gateway.

  3. Fix verification (after fix): Created the same every 5s job. The job took 9.5s to execute. After execution, nextRunAtMs = endedAt + 2000 (exactly MIN_REFIRE_GAP_MS). The math: nextRunAtMs (1774159583382) = lastRunAtMs (1774159571850) + lastDurationMs (9532) + MIN_REFIRE_GAP (2000). The tight refire loop was eliminated.

Human Verification (required)

  • Verified scenarios: (1) Unit tests prove the fix for both daily-interval and short-interval edge cases. (2) Live Docker deployment reproduces the bug with the unfixed image and confirms the fix with the patched image — same gateway, same config, same job parameters.
  • Edge cases checked: Job execution exceeding interval (5s interval, 10–17s execution), lastRunAtMs + everyMs landing exactly at endedAt.
  • What you did not verify: "at" (one-shot) schedule behavior (unchanged code path), interaction with preserveSchedule on branches that have it, or cron-schedule behavior (already had MIN_REFIRE_GAP).

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Revert the single commit; the change is a 3-line removal of an if/else branch.
  • Files/config to restore: src/cron/service/timer.ts — restore the if (job.schedule.kind === "cron") / else branch.
  • Known bad symptoms reviewers should watch for: Every-schedule jobs not firing at all (would indicate MIN_REFIRE_GAP_MS somehow exceeds the interval, but at 2s this is only possible with sub-2s intervals).

Risks and Mitigations

  • Risk: Jobs with very short intervals (<2s) will now fire at most every 2 seconds instead of their configured interval.
    • Mitigation: MIN_REFIRE_GAP_MS is 2 seconds — a reasonable floor. Sub-2s cron intervals are uncommon and would create high load regardless. The same floor already applies to cron-schedule jobs.

🤖 Generated with Claude Code

Changed files

  • src/cron/service/timer.applyJobResult-schedule-catch.test.ts (added, +119/-0)
  • src/cron/service/timer.ts (modified, +17/-9)
RAW_BUFFERClick to expand / collapse

After manually triggering a cron job using cron run command, the job starts repeatedly outside of its schedule.

Steps to reproduce

  1. Create a cron job with schedule 0 16 * * * (once daily at 16:00 UTC)
  2. Manually trigger the job using cron run command
  3. After manual execution, the job continues to run repeatedly at short intervals (every ~5-10 minutes)

Expected behavior

Job should run once and respect its scheduled time (nextRunAtMs).

Actual behavior

Job runs repeatedly after manual trigger, ignoring nextRunAtMs schedule.

Environment

  • OpenClaw version: 2026.3.13
  • Job schedule: 0 16 * * * with timezone UTC

Additional observations

  • The job state shows correct nextRunAtMs (e.g., 22.03 16:00 UTC)
  • But the job still runs at 04:57, 05:06, 05:12 after manual trigger at 04:57
  • Disabling the job stops the repeated execution

extent analysis

Fix Plan

The fix involves modifying the cron job to reset its internal state after manual execution.

Steps to Fix

  • Modify the cron job to update its lastRunAtMs timestamp after manual execution:
import datetime

# Assuming 'job' is the cron job object
job.lastRunAtMs = datetime.datetime.now().timestamp() *

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Job should run once and respect its scheduled time (nextRunAtMs).

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix Cron job runs repeatedly after manual trigger via cron run [1 pull requests, 3 comments, 3 participants]