Skip to content

Cron: drain pending writes before reading run log#25416

Merged
Takhoffman merged 2 commits intoopenclaw:mainfrom
rrenamed:fix/cron-run-log-write
Mar 1, 2026
Merged

Cron: drain pending writes before reading run log#25416
Takhoffman merged 2 commits intoopenclaw:mainfrom
rrenamed:fix/cron-run-log-write

Conversation

@rrenamed
Copy link
Copy Markdown
Contributor

@rrenamed rrenamed commented Feb 24, 2026

Summary

  • Problem: cron runs returns empty results because appendCronRunLog in server-cron.ts is fire-and-forget (void). Reads can race with in-flight writes.
  • Why it matters: Run history is the only way to debug cron behavior. Empty results make crons look broken when they're actually running fine.
  • What changed: Read functions (readCronRunLogEntries, readCronRunLogEntriesPage, readCronRunLogEntriesPageAll) now drain any pending write for the target file(s) before reading.
  • What did NOT change: Write path in server-cron.ts stays fire-and-forget (no async change needed in the event callback). No changes to write serialization, pruning, or file format.

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

User-visible / Behavior Changes

openclaw cron runs now reliably shows recent run entries that were written moments before the read. Previously these could appear missing due to write/read race.

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: Linux (GCP VM) / macOS
  • Runtime/container: Node 22+
  • Relevant config: Any cron job configuration

Steps

  1. Configure a cron job that fires frequently (e.g. */5 * * * *)
  2. Run npx openclaw cron runs --id <job-id> --limit 3 shortly after a cron fires
  3. Observe results

Expected

  • Recent run entry visible immediately

Actual

  • (Before this PR) Returns empty — write hasn't flushed yet

Evidence

  • Failing test/log before + passing after
  • 1 new test: "read drains pending fire-and-forget writes" — fires a non-awaited appendCronRunLog, then reads and asserts the entry is visible
  • All 9 tests pass, pnpm check clean

Human Verification (required)

  • Verified scenarios: fire-and-forget write followed by immediate read returns correct data, existing read/write/prune behavior unchanged (8 existing tests pass)
  • Edge cases checked: readCronRunLogEntriesPageAll drains all file paths, drain on file with no pending write is a no-op
  • What you did not verify: Production load under high-frequency cron writes (but the writesByPath serialization queue is unchanged)

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 commit, reads go back to not draining (same as before)
  • Files/config to restore: None
  • Known bad symptoms reviewers should watch for: Read latency increase if a write is slow (drain awaits it). Unlikely in practice — writes are fast append + optional prune.

Risks and Mitigations

  • Risk: Slow write blocks a read
    • Mitigation: Writes are small JSON appends (~200 bytes), typically < 1ms. Prune only triggers when file exceeds 2MB. Worst case is a single prune delay, same as existing behavior when writes are awaited directly.

Greptile Summary

This PR fixes a race condition where openclaw cron runs returns empty results because fire-and-forget writes from appendCronRunLog can be in-flight when reads occur. The fix adds a drainPendingWrite helper that awaits any pending write promise for a file before reading it.

  • Added drainPendingWrite function in src/cron/run-log.ts:106-112 that checks the writesByPath Map for pending writes and awaits them
  • Updated three read functions (readCronRunLogEntries, readCronRunLogEntriesPage, readCronRunLogEntriesPageAll) to drain pending writes before reading files
  • Added test coverage for the fire-and-forget write scenario showing the drain mechanism works correctly

The implementation is minimal and focused - it only modifies the read path to wait for writes, without changing the existing write serialization queue or the fire-and-forget pattern used in server-cron.ts:297.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is simple, well-tested, and solves a clear race condition. The drainPendingWrite function correctly reuses the existing writesByPath serialization queue without modifying write behavior. The test directly validates the fix scenario (fire-and-forget write followed by immediate read). All existing tests pass, demonstrating backward compatibility. The worst-case performance impact (read blocked by slow write) is mitigated by the fact that writes are fast appends with infrequent pruning.
  • No files require special attention

Last reviewed commit: cc4504b

@Takhoffman Takhoffman merged commit 0cc4658 into openclaw:main Mar 1, 2026
25 checks passed
hwb96 pushed a commit to hwb96/openclaw that referenced this pull request Mar 1, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
github-actions bot pushed a commit to tankerwng2/openclaw that referenced this pull request Mar 1, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
@rrenamed rrenamed deleted the fix/cron-run-log-write branch March 1, 2026 13:44
zooqueen added a commit to hanzoai/bot that referenced this pull request Mar 1, 2026
ansh pushed a commit to vibecode/openclaw that referenced this pull request Mar 2, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
safzanpirani pushed a commit to safzanpirani/clawdbot that referenced this pull request Mar 2, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
robertchang-ga pushed a commit to robertchang-ga/openclaw that referenced this pull request Mar 2, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
hanqizheng pushed a commit to hanqizheng/openclaw that referenced this pull request Mar 2, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
dorgonman pushed a commit to kanohorizonia/openclaw that referenced this pull request Mar 3, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
sachinkundu pushed a commit to sachinkundu/openclaw that referenced this pull request Mar 6, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
zooqueen added a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
Mateljan1 pushed a commit to Mateljan1/openclaw that referenced this pull request Mar 7, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 16, 2026
* Cron: drain pending writes before reading run log

* Retrigger CI

(cherry picked from commit 0cc4658)
alexey-pelykh added a commit to remoteclaw/remoteclaw that referenced this pull request Mar 16, 2026
…1519)

* Cron: drain pending writes before reading run log

* Retrigger CI

(cherry picked from commit 0cc4658)

Co-authored-by: Aleksandrs Tihenko <[email protected]>
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.

2 participants