fix(ci): serialize concurrent cargo cache mounts with sharing=locked (FJCLI-47) #60
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/FJCLI-47-cargo-cache-sharing-locked"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes the
build-binary.ymlfailure onmain(run #287, FJCLI-47): a BuildKit cargo-cache race that surfaced right after the FJCLI-45 MCP merge.Root cause
build-binary.yml(Linux) andbuild-binary-windows.yml(Windows) trigger on the samecrates/**/Cargo.*/oci-build/**paths, so the post-merge push tomainran both concurrently on one runner. Both Dockerfiles mount the cargo registry/git BuildKit caches at the same target path (/usr/local/cargo/registry), which is the default cache id, so they share one cache. BuildKit defaults tosharing=shared, and cargo's.package-cacheextraction lock lives in the ephemeral$CARGO_HOME(not on the cached mount), so the two builds cannot see each other's lock. They raced unpacking the same crate and collided on.cargo-ok:failed to open .cargo-ok / File exists (os error 17).The MCP merge added the
fj-mcpdependency tree (schemars,serde_derive_internals,icu_*), which enlarged the concurrent fresh-download window enough to trip a race that was latent before.Fix
Add
sharing=lockedto all eight cargo cache mounts acrossoci-build/Dockerfileandoci-build/Dockerfile.windowsso concurrent builds serialize through the shared cache instead of racing. This is exactly the fix already present in the siblingpandoras-box/forgejo-mcpDockerfiles, which run three concurrent builds on one runner. The two cache-using RUNs within a single Dockerfile are already sequential, so the lock adds no cost there.This supersedes the auto-triage's "clear the runner cache" suggestion with a durable source-level fix that prevents recurrence.
Completeness sweep
Invariant: every cargo registry/git cache mount a concurrent build can touch must declare
sharing=locked. Grep ofoci-build/found 8 mounts (registry + git, in the prime and real build RUNs of each Dockerfile); all 8 weresharedand are nowlocked. No exclusions.Testing
just check-docker(builder-stage compile ofoci-build/Dockerfilewith the locked mounts): green, image exported.just pre-commit(fmt + clippy + build + full test suite): green (no Rust changed).One-time infra note
The runner's cargo registry cache volume may still hold the half-unpacked
serde_derive_internalsentry from the failed run. A one-time prune of that BuildKit cache clears it; after that,sharing=lockedprevents the race from recurring.