fix(build): give every cargo cache mount a per-image id and sharing=locked #533

Merged
Claude-Run merged 1 commit from fix/BUNYIP-534-cache-mount-sharing into main 2026-08-13 19:24:42 +02:00
Member

The v0.14.0 bunyip-web release build died with failed to open .../.cargo-ok: File exists (os error 17). A release commit fires both a main push and a v* tag push, so two build-web and two build-api runs execute at once on one buildkit instance, and every --mount=type=cache in the repo was unnamed and sharing=shared: keyed by target path alone, so all four builds unpacked crates into the same /usr/local/cargo/registry. Cargo cannot serialise them because its .package-cache lock lives at $CARGO_HOME/.package-cache, outside the mounted subdirectories, so each build takes an uncontended lock.

All 7 cache mounts now carry a per-image id= (bunyip-{api,web}-cargo-{registry,git}) and sharing=locked. The distinct ids keep the api and web builds fully parallel with their own warm registries; the lock queues the remaining real overlap, two runs of the same image for one release commit, instead of letting them corrupt the cache.

Neither annotation is load-bearing at build time, so a new unannotated mount would build fine and only fail months later under release concurrency. scripts/check-cache-mount-sharing.nu gates every tracked Dockerfile with a file-and-line message, carries a --self-test covering the bare, id-less, sharing-less, sharing=shared and empty-id shapes, and runs in check.yml and just check.

#BUNYIP-534

The v0.14.0 bunyip-web release build died with `failed to open .../.cargo-ok: File exists (os error 17)`. A release commit fires both a `main` push and a `v*` tag push, so two build-web and two build-api runs execute at once on one buildkit instance, and every `--mount=type=cache` in the repo was unnamed and `sharing=shared`: keyed by target path alone, so all four builds unpacked crates into the same `/usr/local/cargo/registry`. Cargo cannot serialise them because its `.package-cache` lock lives at `$CARGO_HOME/.package-cache`, outside the mounted subdirectories, so each build takes an uncontended lock. All 7 cache mounts now carry a per-image `id=` (`bunyip-{api,web}-cargo-{registry,git}`) and `sharing=locked`. The distinct ids keep the api and web builds fully parallel with their own warm registries; the lock queues the remaining real overlap, two runs of the same image for one release commit, instead of letting them corrupt the cache. Neither annotation is load-bearing at build time, so a new unannotated mount would build fine and only fail months later under release concurrency. `scripts/check-cache-mount-sharing.nu` gates every tracked Dockerfile with a file-and-line message, carries a `--self-test` covering the bare, id-less, sharing-less, `sharing=shared` and empty-id shapes, and runs in `check.yml` and `just check`. #BUNYIP-534
fix(build): give every cargo cache mount a per-image id and sharing=locked
All checks were successful
E2E / PR gate (pull_request) Successful in 31s
Check / fmt + clippy + build + tests (pull_request) Successful in 15m8s
Create release / Create release from merged PR (pull_request) Has been skipped
4062a1750b
The v0.14.0 bunyip-web release build died with `failed to open .../.cargo-ok: File exists (os error 17)`. A release commit fires both a `main` push and a `v*` tag push, so two build-web and two build-api runs execute at once on one buildkit instance, and every `--mount=type=cache` in the repo was unnamed and `sharing=shared`: keyed by target path alone, so all four builds unpacked crates into the same `/usr/local/cargo/registry`. Cargo cannot serialise them because its `.package-cache` lock lives at `$CARGO_HOME/.package-cache`, outside the mounted subdirectories, so each build takes an uncontended lock.

All 7 cache mounts now carry a per-image `id=` (`bunyip-{api,web}-cargo-{registry,git}`) and `sharing=locked`. The distinct ids keep the api and web builds fully parallel with their own warm registries; the lock queues the remaining real overlap, two runs of the same image for one release commit, instead of letting them corrupt the cache.

Neither annotation is load-bearing at build time, so a new unannotated mount would build fine and only fail months later under release concurrency. `scripts/check-cache-mount-sharing.nu` gates every tracked Dockerfile with a file-and-line message, carries a `--self-test` covering the bare, id-less, sharing-less, `sharing=shared` and empty-id shapes, and runs in `check.yml` and `just check`.

#BUNYIP-534
Claude-Run deleted branch fix/BUNYIP-534-cache-mount-sharing 2026-08-13 19:24:42 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/bunyip!533
No description provided.