Race condition: concurrent builds clobber each other's external dep clones #2
Labels
No labels
bug
claude:done
claude:failed
claude:in-progress
claude:ready
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Catcrafts/Crafter.Build#2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
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?
When two
crafter-buildinvocations run concurrently and both need the sameexternal dep, they race on the shared
.tmpclone directory and one corruptsthe other's in-flight git clone.
Repro
Two projects (A, B) that both declare the same
ExternalDependency(directlyor transitively), sharing a common
~/.cache/crafter.build/external/:If the cache miss happens for both at roughly the same moment, one of the
builds fails.
Observed
tmp_pack_*is an in-flight git pack tempfile — it vanishes mid-read becausethe other build either rm'd the
.tmpdirectory or finished and renamed itout from under us.
Likely cause
The cache path is derived from a hash of the dep spec, so concurrent builds
that resolve to the same external compute the same
.tmpdirectory name(both racing builds picked the identical
-<hash>.tmpsuffix in the failurewe hit). There's no lock around
git clone → rename, so:git clone … .tmp(in progress)git clone … .tmp(sees existing dir, or wipes-and-retries)invalid index-pack outputSuggested fixes
<dep>.tmp.<pid>(ormktemp -d),then
rename(2)to the canonical cache path on success.renameis atomicon the same filesystem; the loser of the race just discards its clone.
flockon~/.cache/crafter.build/external/<dep>.lockaround the clone+rename soonly one builder actually fetches; others wait and reuse the result. Lower
bandwidth usage when many builds start at once.
(1) alone fixes the corruption; (1) + (2) also avoids redundant clones.
Environment
crafter-buildinvocations against sibling projects thatshare the user's
~/.cache/crafter.build/external/claude:claim:b831bbc6-27c5-4963-87be-6b4dce043c86
[progress]
[progress]
[progress]
[progress]
PR opened: #3