Let cancel terminate auxiliary build phases instead of blocking the slot

Cancelling a build only killed the running build process; the synchronous
preparation phases — most notably a multi-minute Docker image build, but also
the Gradle-volume preparation — ran to completion and kept the concurrency
slot occupied, so the next queued build stayed PENDING for a long time.
Build runners now report every auxiliary process through an onAuxProcess sink
(GitCommandRunner gained an onProcess hook), and the executor registers them
like the build process, so cancellation terminates whatever is currently
running. Measured on vm4006: cancel to next-build-running is ~3s in the
normal case; the unit test covers the aux-phase case.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-10 16:14:38 +02:00
co-authored by Claude Fable 5
parent 76321a6f5c
commit ed9562d1a7
8 changed files with 107 additions and 23 deletions
@@ -48,12 +48,13 @@ class DockerBuildRunner(
environment: Map<String, String>,
repoDir: Path,
branchConfig: BranchConfig,
onAuxProcess: (Process) -> Unit,
): Process {
val docker = branchConfig.docker
require(docker.image.isNotBlank()) { "branches.<name>.docker.image must be set when docker.enabled is true" }
val repoKey = ArtifactKeys.repoKey(repoDir)
cleanupStaleContainersOnce(repoKey, repoDir)
ensureImage(docker, repoDir)
ensureImage(docker, repoDir, onAuxProcess)
val uid = id("-u", repoDir)
val gid = id("-g", repoDir)
val socket = socketLocator.locate(uid)
@@ -64,7 +65,7 @@ class DockerBuildRunner(
val ownershipUid = if (rootless) "0" else uid
val ownershipGid = if (rootless) "0" else gid
val volume = gradleVolumeName(repoKey)
prepareGradleVolume(volume, docker.image, ownershipUid, ownershipGid, repoDir)
prepareGradleVolume(volume, docker.image, ownershipUid, ownershipGid, repoDir, onAuxProcess)
val containerName = containerName(repoKey, environment["branch"])
removeContainer(containerName, repoDir)
val runCommand =
@@ -92,6 +93,7 @@ class DockerBuildRunner(
private fun ensureImage(
docker: DockerConfig,
repoDir: Path,
onAuxProcess: (Process) -> Unit,
) {
if (docker.dockerfile.isBlank()) {
return
@@ -126,6 +128,7 @@ class DockerBuildRunner(
docker.context,
),
repoDir,
onProcess = onAuxProcess,
)
}
@@ -140,6 +143,7 @@ class DockerBuildRunner(
uid: String,
gid: String,
repoDir: Path,
onAuxProcess: (Process) -> Unit,
) {
val key = "$volume@$image"
if (key in preparedVolumes) {
@@ -164,6 +168,7 @@ class DockerBuildRunner(
gid,
),
repoDir,
onProcess = onAuxProcess,
)
preparedVolumes += key
}