Repository navigation
feat(run): keep running independent tasks after a failure with --continue - #898
jasonkuhrt wants to merge 5 commits into
Conversation
…inue Without the flag, a failed task cancels the run as before. With `--continue`, a failure cancels nothing: running tasks aren't killed, new tasks keep being scheduled, and tasks that succeed are cached. The scheduler now carries whether a node failed. A failed node doesn't release its dependents, so they never start and, like tasks that fast-fail never started, aren't reported. A node stops at its first failed `&&` item, and a nested graph with a failed node counts as its parent item failing. The reporter already decides the exit status: the failed task's exit code for one failure, 1 for several. Part of voidzero-dev#822. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QwWB8aXGe9BR2dR8KLH9RW
|
I'm not sure why this behavior is guarded behind a If the concern is that even when a task failed, its output may be the one contributing to other failures, simply not caching the entire graph when there is a failure, while reporting accurate exit codes for individual task seems to be a sensible default that provides the maximum amount of information. |
`--continue` is now resolved for each `vp run` level, like `--concurrency-limit`. A `vp run --continue` in a task's script applies to the tasks it runs, even when the outer run has no `--continue`, and an outer `--continue` carries over to nested runs, including ones a task starts as a separate process, through `VP_RUN_INTERNAL_CONTINUE`. The task selector keeps the flag too. The fast-fail token stays global, and graphs with `--continue` obey it. Only graphs without `--continue` cancel it, from the graph loop instead of `execute_leaf`, so a nested `--continue` run that failed also stops a fast-fail parent. A nested flag can only turn continue on, so a single token gives the same result as one per level. Each spawn gets a child token, so a task that fails to forward its output only kills its own process. `--no-bail`, pnpm's name for the same behavior, is a hidden alias. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # CHANGELOG.md # crates/vt_bin/src/vtt/main.rs
With `--continue`, a task's exit never cancels the run, so stopping new tasks after Ctrl-C depends only on the Ctrl-C token. The new case presses Ctrl-C while `a` runs: `a` exits 0, and `b`, which depends on it, must not start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
I still prefer fail-fast by default simply because it gives faster feedback. Most of the time we just want to know anything (not everything) that goes wrong. I also added a @fengmk2 @cpojer Do fail-fast by default and |
@wan9chi fail-fast by default and Fast feedback and the cache don't have to be traded against each other. Today A failure is reported only when the run ends. In this PR's own snapshot, The small fix is a line printed the moment a task fails, in every log mode, e.g. The full fix is a run event log. {
"event": "task_finished",
"task": "pkg-c#failing",
"exit_code": 42,
"cache": "miss",
"log": "<cache>/logs/pkg-c#failing.log"
}An agent or a CI step that tails the file can start on a failure the moment it lands and read only that task's output, while the rest of the run finishes and is cached. Task output never shares stdout with the JSON, as the rule for JSON output asks. Fail-fast can stay the default for people at a terminal, and automation passes Fail-fast kills the tasks in flight (exit 137, not cached), so the next run starts them over. Make and Cargo fail fast without that ( |
LGTM. Besides enabling it through a command-line flag, can it also be enabled in the task config? |
Motivation
When a task fails,
vp runcancels the whole run. Tasks that are still running are killed with exit code 137, no new task starts, and none of them gets a cache entry. In a recursivelintortestover many packages, the first failure hides every other package's result, and the killed tasks run again from nothing next time. #822 asks for an option to keep going.This PR is the first step of #822. Tasks that depend on a failed task don't run and aren't listed, the same way fast-fail already treats the tasks it never started. Listing them as skipped, as #822 proposes, needs decisions about the reporter and the summary format, so it's left for a follow-up.
Part of #822.
flowchart TB subgraph today["Today: a failure cancels the run"] direction TB g1["db#generate<br/>failed"]:::failed --> a1["api#lint<br/>not run"]:::notrun g1 --> w1["web#lint<br/>not run"]:::notrun u1["utils#lint<br/>killed, exit 137, not cached"]:::failed end subgraph cont["With --continue"] direction TB g2["db#generate<br/>failed"]:::failed --> a2["api#lint<br/>not run"]:::notrun g2 --> w2["web#lint<br/>not run"]:::notrun u2["utils#lint<br/>passed, cached"]:::passed end classDef failed fill:#FCEBEB,stroke:#A32D2D,color:#791F1F classDef passed fill:#EAF3DE,stroke:#3B6D11,color:#27500A classDef notrun fill:#F1EFE8,stroke:#5F5E5A,color:#444441Both runs exit with a non-zero status. Today
utils#lintis reported as failed (137) and runs again next time. With--continueit is cached, andapi#lintandweb#lintaren't listed, as with fast-fail today.Change
vp rungets a--continueflag (RunFlags::continue_on_failure). Without it, nothing changes.With it, a failed task doesn't cancel
fast_fail_token. Running tasks aren't killed, new tasks keep being scheduled, and tasks that succeed are cached through the existing path. Ctrl-C still cancels everything.In the scheduler,
execute_leaf,execute_nodeandexecute_expanded_graphnow return whether they failed. A failed node doesn't release its dependents, so their dependency counts never reach zero and they never start, directly or through other tasks. A node stops at its first failed&&item. A task whose script runsvp runfails if any task in that nested graph fails, so its own dependents don't start either.The exit status needs no change: once every task that can run has finished, the reporter already exits with the failed task's exit code for one failure, and 1 for several.
New
exit_codessnapshot cases cover a task that finishes and is cached beside a failure and replays from the cache on the next run, dependents of a failure and of a failure in a nestedvp run, a&&chain that stops at its failure, and the exit code with two failures.docs/cancellation.mddescribes the flag in its Fast-fail section.