Skip to content

Commit 9478e2d

Browse files
authored
ci: serialize uv installs against the shared node-local cache (#1630)
1 parent 8553cc9 commit 9478e2d

1 file changed

Lines changed: 40 additions & 2 deletions

File tree

toolchain/bootstrap/python.sh

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,11 +188,49 @@ if ! cmp "$(pwd)/toolchain/pyproject.toml" "$(pwd)/build/pyproject.toml" > /dev/
188188
if [ "${GITHUB_ACTIONS:-}" = "true" ] && [ -w "${TMPDIR:-/tmp}" ]; then
189189
export UV_CACHE_DIR="${TMPDIR:-/tmp}/uv-cache-${USER:-$(id -un)}"
190190
fi
191+
192+
# uv's cache (~/.cache/uv by default, or the node-local redirect above
193+
# in CI) is shared per-user across every repo/worktree/matrix leg. uv's
194+
# own cache lock protects individual entries, but concurrent installs
195+
# from separate uv processes can still race while one extracts/prunes
196+
# the shared archive-v0 store, leaving a corrupted entry (e.g. a
197+
# missing dist-info METADATA file) that fails every subsequent install
198+
# until the cache is manually cleared -- both across self-hosted CI
199+
# matrix legs (Frontier, Phoenix) sharing a login node, and across
200+
# concurrent local builds by the same user. Serialize the install
201+
# call itself so only one uv process touches a given cache dir at a
202+
# time. Fall back to /tmp for the lock file itself if TMPDIR isn't
203+
# writable (e.g. a stale TMPDIR left over from a prior job's
204+
# since-deleted scratch dir), so a bad TMPDIR can't break installs
205+
# that used to work fine before this lock existed.
206+
UV_LOCK_DIR="${TMPDIR:-/tmp}"
207+
[ -d "$UV_LOCK_DIR" ] && [ -w "$UV_LOCK_DIR" ] || UV_LOCK_DIR=/tmp
208+
UV_INSTALL_LOCK="${UV_LOCK_DIR}/mfc-uv-install-${USER:-$(id -un)}.lock"
209+
if command -v flock > /dev/null 2>&1; then
210+
uv_install() { flock "$UV_INSTALL_LOCK" uv pip install "$@"; }
211+
else
212+
uv_install() { uv pip install "$@"; }
213+
fi
214+
215+
# A cache entry corrupted before this lock existed (or by any other
216+
# cause) will otherwise fail every subsequent install until someone
217+
# notices and clears the cache by hand -- which is exactly what
218+
# happened here (a stale corrupted entry on a self-hosted runner kept
219+
# failing across multiple PRs before anyone caught it). Self-heal: on
220+
# the first failure, clear the cache and retry once before giving up.
221+
uv_install_with_retry() {
222+
if uv_install "$@"; then
223+
return 0
224+
fi
225+
warn "(venv) uv install failed; clearing the uv cache and retrying once, in case a corrupted cache entry is the cause..."
226+
uv cache clean > /dev/null 2>&1 || true
227+
uv_install "$@"
228+
}
191229
log "(venv) Using$MAGENTA uv$COLOR_RESET for fast installation..."
192230

193231
if [ "$verbose" = "1" ]; then
194232
# Verbose mode: show full uv output
195-
if uv pip install "$(pwd)/toolchain"; then
233+
if uv_install_with_retry "$(pwd)/toolchain"; then
196234
ok "(venv) Installation succeeded."
197235
cp "$(pwd)/toolchain/pyproject.toml" "$(pwd)/build/"
198236
else
@@ -203,7 +241,7 @@ if ! cmp "$(pwd)/toolchain/pyproject.toml" "$(pwd)/build/pyproject.toml" > /dev/
203241
fi
204242
else
205243
# Default: show progress but filter out individual package lines (+ pkg==ver)
206-
uv pip install "$(pwd)/toolchain" > "$PIP_LOG" 2>&1
244+
uv_install_with_retry "$(pwd)/toolchain" > "$PIP_LOG" 2>&1
207245
UV_EXIT=$?
208246
# Show filtered output (progress info without package list)
209247
# Filter out lines like " + pkg==1.0", " - pkg==1.0", " ~ pkg==1.0"

0 commit comments

Comments
 (0)