Follow-up of #95: the × of a queued build set only a flag, and the row stayed pending until the build ahead of it finished (hours behind a mutation build); a restart in between re-ran it. - `cancel` decides under the build lock: a queued build is recorded CANCELLED at once and leaves the active builds; a running one is killed as before. - `execute` skips a build cancelled in the queue, before and after waiting for a slot. Version: v1.30.3, because #97 (open) also claims v1.30.2. PR-doc: `docs/prs/2026-10-03-PR#98-cancel-queued-build-at-once.md` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: mhoennig <michael@hoennig.de> Reviewed-on: #98
54 lines
2.5 KiB
Markdown
54 lines
2.5 KiB
Markdown
> **WARNING:** This document describes only the change applied in this PR.
|
||
> It may already be outdated once the next PR is merged.
|
||
> Historic PR-documentation is not maintained along with new PRs — treat it as a snapshot, not as current documentation.
|
||
|
||
## The Problem
|
||
|
||
Since PR#95 the × of a queued build cancels it.
|
||
The executor only set a flag, and the result became CANCELLED when the branch's worker reached the build.
|
||
Behind a running build of the same branch, or while no slot was free, that took as long as the build ahead of it ran: hours behind a mutation build.
|
||
The row said "pending" all that time, although the build would never run.
|
||
A restart in between was worse: the startup recovery re-enqueues every PENDING result, so the cancelled build ran after all.
|
||
|
||
## The Scenarios
|
||
|
||
### Feature: A queued build that is cancelled is recorded at once
|
||
|
||
#### Scenario#98.01: Cancelled behind a running build of its branch
|
||
|
||
So that the row says what will happen, not what was planned.
|
||
|
||
- **Given** a running build and a second build of the same branch queued behind it
|
||
- **When** the queued build is cancelled
|
||
- **Then** its result is CANCELLED at once, while the first build still runs
|
||
- **And** it is no longer active, and its worker skips it: no worktree, no second status
|
||
|
||
##### Verified by
|
||
|
||
- [BuildExecutorIntegrationTest](../../src/test/kotlin/de/hoennig/werkator/build/BuildExecutorIntegrationTest.kt) — Scenario#98.01
|
||
|
||
#### Scenario#98.02: Cancelled while it waits for a free slot
|
||
|
||
So that the slot wait ends the same way as the branch wait.
|
||
|
||
- **Given** a build of another branch that waits for the only slot
|
||
- **When** it is cancelled
|
||
- **Then** its result is CANCELLED at once
|
||
- **And** the same commit can be queued again at once
|
||
|
||
##### Verified by
|
||
|
||
- [BuildExecutorIntegrationTest](../../src/test/kotlin/de/hoennig/werkator/build/BuildExecutorIntegrationTest.kt) — Scenario#98.02
|
||
|
||
## The Solution
|
||
|
||
- `BuildExecutor.cancel` decides under the build's lock whether the build is queued or executing.
|
||
A queued build is recorded as CANCELLED, its (empty) artifacts are stored, and it leaves the active builds — the order `execute` uses.
|
||
An executing build has its process tree terminated, as before.
|
||
- `execute` checks the flag before it waits for a slot and, under the same lock, before it starts; a build cancelled in the queue returns without a status of its own.
|
||
- The recovery no longer finds the build, because its result is no longer PENDING.
|
||
|
||
## Additional Changes
|
||
|
||
- Version 1.30.3 with its release note.
|