feat(batch): --auto-restart supervisor and clawbench-batch-watch alerting - #355
Open
vaibhavdabas16 wants to merge 3 commits into
Open
feat(batch): --auto-restart supervisor and clawbench-batch-watch alerting#355vaibhavdabas16 wants to merge 3 commits into
vaibhavdabas16 wants to merge 3 commits into
Conversation
A multi-hour batch dies for reasons unrelated to the agent: an OOM-killed container, a thirty-second provider outage, a queue cap at task 75. The batch process is gone, so nothing inside it can retry, and the cell sits on the leaderboard as "partial" until someone notices (TIGER-AI-Lab#160). `--auto-restart N` runs the batch under a supervisor that spawns it as a child and, on non-zero exit, waits and re-invokes it with --resume into the same batch directory, up to N times. The directory is created before the first attempt so every attempt — including the first — resumes into one place. The supervisor holds no browser, containers, or model calls, which is why it survives what the batch does not. Ctrl-C is never retried. The supervisor lives in its own module; batch.py gains only the flags and a hand-off in main(), so it does not touch the resume logic that TIGER-AI-Lab#329 changes.
Polls a batch directory and posts to a Slack or Discord webhook when the batch aborts (last task, error tail from the newest log, elapsed time), completes (pass/total, wall-clock), and optionally every N completed tasks. It reads only the artifacts the batch already writes, so it needs nothing from the batch process itself. Abort is detected from --pid when given, else from a stall timeout on artifact activity. The liveness probe is deliberately not os.kill(pid, 0): on Windows that call terminates the process, because any signal other than the Ctrl events is passed to TerminateProcess as an exit code. Routing is per operator via ~/.config/clawbench/notify.toml, overridden by flags; the payload carries both `text` and `content` so one webhook shape serves Slack and Discord.
Covers how to resume a batch, what --auto-restart does and does not promise, how to set up clawbench-batch-watch, and what survives an abort (every run that reached run-meta.json) versus what does not (the task in flight, which is re-run from scratch). Tests cover the supervisor's restart loop, give-up bound, interrupt handling, flag stripping, and CLI hand-off, and the watcher's snapshot, completion/abort/heartbeat decisions, pid probe, config precedence, and --once mode.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Advances #160. Meets three of its five acceptance criteria —
--auto-restart N, theclawbench-eval-watchskeleton (namedclawbench-batch-watchhere, matching theclawbench-batchfamily), anddocs/operations.md. The two remaining are real-run tests (Test 1 / Test 2) that need a multi-hour batch and are not something I can do from here; the doc states Test 2's semantics explicitly.--auto-restart NThe key design point: the batch process cannot retry its own death. An OOM-killed container, a
SIGKILL, an unhandled exception — the process is gone. So this is not a retry loop insideasync_main; it's a supervisor that spawnsclawbench-batchas a child and, on non-zero exit, waits and re-invokes it with--resumeinto the same batch directory, up to N times.--resumecan be passed explicitly to supervise an existing batch.130.0only when an attempt finished with every job terminal.runner/supervise.py;batch.pygains only the two flags and a hand-off inmain(). It does not touch the resume logic, so there's no overlap with fix(batch): resume from run-meta.json, not from log-file existence #329.One honest dependency: today's
--resumetreats any job with a log file as done, including errored ones (#297). So after a batch that completed with infra errors, a restart currently resumes-and-skips them rather than retrying. Once #329 lands, restart automatically retries failed jobs — that's the "network blip" case in #160 — with no change needed here. For the abort case (process died mid-run) it works correctly today.clawbench-batch-watchPolls a batch directory and posts to a webhook on abort (last task, error tail from the newest log, elapsed), completion (pass/total, wall-clock), and optionally a heartbeat every N tasks. It reads only artifacts the batch already writes —
run-meta.json,batch-logs/*.log,batch-summary.json— so it needs nothing from the process.--pidgone without a summary, or--stall-timeout(default 45 min) with no artifact activity.~/.config/clawbench/notify.toml(webhook_url,interval_s,heartbeat_every,stall_timeout_s), flags override.tomllibis stdlib on 3.11+, and the POST usesurllib— no new dependency (the issue mentionsrequests, but the repo doesn't have it).textandcontent, so one webhook shape serves Slack and Discord.os.kill(pid, 0). On Windows,os.killwith any signal other than the Ctrl events callsTerminateProcesswith that value as the exit code — the standard POSIX liveness idiom would kill the batch it was watching. The Windows path usesOpenProcess/GetExitCodeProcessinstead, and there's a test that probes a live and a dead pid.Testing
tests/test_batch_resilience.py— 16 cases: the supervisor's restart-until-success loop (same--resumedir on every attempt, sleeps only between retries), the N+1 attempt bound, no-restart-on-interrupt, flag stripping so the child never recurses, and an end-to-end check thatclawbench-batch --auto-restarthands off to the supervisor rather than running in-process; the watcher's snapshot counts, quiet-while-healthy, completion, pid-gone abort with error tail, stall abort, heartbeat-without-repeat, pid probe, TOML/flag precedence, and--once.clawbench.runner.watchis added to the CLI help-module test.Full suite:
292 passed, 10 skippedlocally;ruffandpyrightclean on the new files.