Files
42eb6ab5fb fix(cron): bound run history and read recent records from the tail (#1094)
* fix(cron): bound run history and read recent records from the tail

Retain the newest 1,000 outcomes under the job lock and publish complete history snapshots. Add bounded reverse reads and regression coverage for legacy logs, failures, and concurrent stores.

Fixes Gitlawb/zero#1086

Amp-Thread-ID: https://ampcode.com/threads/T-01a0dcd6-ad63-74d8-8396-45573c57dcec
Co-authored-by: Pierre Bruno <[email protected]>

* fix(cron): skip oversized legacy history records

Discard entire oversized lines during bounded tail reads so compaction can record new outcomes without weakening atomic publication. Cover exact size boundaries and oversized first, middle, and unterminated final records.

Amp-Thread-ID: https://ampcode.com/threads/T-01a0e861-ebee-7764-be1d-e67517cd914c
Co-authored-by: Pierre Bruno <[email protected]>

* fix(cron): append the outcome when the history log cannot be replaced

On Windows the atomic replace of runs.jsonl fails while another process
holds the log open, which dropped every outcome for as long as it stayed
open. Keep the replace, and only when it fails append the record on a
fresh line. The leading newline terminates any unterminated tail; the
blank line it may leave is already skipped by readRuns. Zero's own
readers take the job lock, so they never observe a partial append.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

* fix(cron): preserve the history DACL and append only on sharing violations

Compacting runs.jsonl renamed a temporary file over it, which on Windows
replaced a DACL applied to the log with the job directory's inherited
one. Publish through ReplaceWithRetry so the log keeps its descriptor.

Fall back to appending only when the replace fails with a Windows
sharing or lock violation, the error a reader holding the log open
produces. Any other failure, such as a persistent access denial, is
returned so a log that can never be replaced cannot grow past the
retention limit. fsutil.IsSharingOrLockViolation exposes the existing
classifier, gated to Windows because errno 32 and 33 mean EPIPE and EDOM
elsewhere.

Co-Authored-By: Claude Opus 5.5 <[email protected]>

---------

Co-authored-by: Amp <[email protected]>
Co-authored-by: Claude Opus 5.5 <[email protected]>
2026-10-12 09:45:29 +08:00
..