Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

#170

Stop a run that is already going

merged · by keenan 6d ago · merged into main at 70291860 by keenan 6d ago

keenan opened this 6d ago

What

The run page offers Stop running run on a run a runner has picked up. Clicking it records the request and leaves the lease where it is. The runner sees the request on the heartbeat it already sends, stops the container, writes one line to the job log, and reports the attempt it had so far. The run stays canceled, keeps its partial log and step timings, and its page says who asked and that it was stopped rather than failed.

A queued run is still canceled outright, and its page now names the account too.

Why

Canceling a queued run was the only way to stop work, and the comment above CancelRun said why: the queue does not own the process. So a build that was clearly wrong — an LLM session on the wrong track, a retry loop, a test suite that will never finish — held its runner until the step timeout, the job budget from #161, or somebody killing the container by hand. None of those is a minutes-scale answer.

This is the second half of §3 of #138.

Shape

  • Queue (ci/runs): cancel_requested and cancel_actor are additive columns on runs. CancelRunning sets them and touches nothing else; Heartbeat returns the account as cancel. RecordAttempt and Finish keep the canceled status when the marker is set, so the runner’s nonzero exit code does not turn the run into a failure. The expiry sweep cancels a marked run whose runner died instead of queueing it again, and Requeue clears the marker because a rerun is a new decision.
  • Runner (ci/agent): the heartbeat reply gains cancel; a step or an image build that sees it kills the process group, stops the container, logs one line, and reports the partial attempt. A lost lease is still a lost lease: no report.
  • Web (server/web): one action, with the outcome chosen from the run’s status. The button names what it will do, and the page names the account and distinguishes a run stopped while running from one canceled in the queue. Audit keeps its shape: the account, the repository, and the run.
  • Gate: no change needed — a canceled run already does not count as a check and is not a wait, which forge/landing already tested.

Tests

  • ci/runs: a stop request keeps the lease and reaches the heartbeat; a record and a plain finish both keep canceled; the expiry sweep cancels a request whose runner died; a rerun clears it; a queued cancel names the account.
  • server/ssh: the request crosses a real SSH channel on the heartbeat reply, and the stopped attempt is stored.
  • server: the browser action on a running run, the stopping state, and the page after the runner reports.

Checks

  • vole workflow run verify passes, including the race test suite, vet, build, license and reachability scans, packaging, and link checks.
  • vole workflow check passes.

Closes #162.

Discussion (2)

keenan 6d ago

You were right: the first commit broke #168’s promise. Stopping a running run had become an action only the browser offered. Fixed in deb024d.

  • vole run cancel <id> [--remote <name|url>] cancels a queued run or asks a running one to stop. The id is the 26-character one in the run page URL.
  • The CLI asks over the key it already pushes with (vole-run-cancel <repository> <run-id>), and the server checks the same CanTriage maintainer capability the page checks before touching the queue.
  • The audit action is now run.cancel for both transports; the web action was renamed from web.run.cancel so one action has one name. An operator looking for canceled runs should not have to know which surface asked.
  • Tests: a real SSH channel cancels a running run and the heartbeat reply carries the request; a read-only account is refused with the missing capability named; the audit line names the account, the repository, and the run. vole workflow run verify passes.

The request description still describes the web half; this comment is the CLI half.

One pre-existing gap remains, which this request does not touch: Rerun is still browser-only. If “the same actions” should cover that too, it needs its own verb (vole run rerun) and the same maintainer check.

keenan 6d ago

Rerun is in 7029186, so the gap I named above is closed.

  • vole run rerun <id> [--remote <name|url>] queues a finished run again with the job it already pinned. A queued or running run is refused, because that would run the same job twice rather than queue it again.
  • Both verbs share one target resolver, so a repository or run refused for cancel is refused for rerun with the same words, and both check the same CanTriage capability the page checks.
  • Audit actions are run.cancel and run.rerun for both transports; the web’s web.run.rerun was renamed for the same reason as cancel.
  • Tests cover rerunning a finished run over SSH, refusing a running one, and the audit record. vole workflow run verify passes on 7029186.

The request now offers the same two run actions through either transport.