Repository navigation
[Merged by Bors] - fix(cache): time out stalled downloads and retry hard failures in a fresh pass - #45096
[Merged by Bors] - fix(cache): time out stalled downloads and retry hard failures in a fresh pass#45096marcelolynch wants to merge 39 commits into
Conversation
curl below 8.14.0 truncates the output file before it retries a transfer that received a body. It cannot truncate the null device, so it abandons the transfer without a retry or a report (curl issue leanprover-community#17371). The upload now sends every response body to one regular file. The jobs that run the cache tool on a GitHub runner use ubuntu-24.04 and have a timeout: curl 8.18.0 on ubuntu-26.04 hangs on a pending retry in parallel mode (curl issue leanprover-community#20669).
…obs on ubuntu-latest curl 8.18 hangs on a pending retry in parallel mode (curl issue leanprover-community#20669), and Ubuntu 26.04 ships it. The tool already downloads a static curl for versions that are too old; 8.18 now takes the same path. The upload and Post-Build jobs get a timeout.
Name the error first, then add a note or a hint. Use one message for every failure case.
…UploadFix # Conflicts: # Cache/CI.md
curl 8.18 and 8.19 hang on a pending retry in parallel mode (curl issue leanprover-community#20669). The download path now treats them like an old curl: Linux fetches the static binary, other platforms run serial downloads. Uploads already require curl 8.20.
Uploads require curl 8.20. curl 8.14 fixed the retry of a transfer that received a body while writing to the null device (curl issue leanprover-community#17371), so the shared regular-file sink is unnecessary.
`test_curlGetWriteOut_real_curl` runs one curl `file://` copy.
The release has x86_64 and aarch64 assets. The binary's file name carries the version, so an existing download refreshes once.
Ubuntu 26.04 ships curl 8.18, which the tool rejects for parallel transfers, so the Linux job covers the static curl fallback. The Windows job covers the download path with the system curl. actionlint does not know the ubuntu-26.04 label yet; the config file declares it.
After the location chain, walk it once more over the hard failures that no location served, in a fresh curl. curl's own retries share one process's connection pool, and a reset pool stalls all six attempts while the sibling transfers of the same run complete. The exit code counts the failures left after that pass.
PR summary afeb1e2b37Import changes for modified filesNo significant changes to the import graph Import changes for all files
|
actionlint reads one config file, and a new actionlint.yaml shadowed the existing actionlint.yml with the self-hosted labels.
curl 8.18 and 8.19 hang on a pending retry in parallel mode (curl issue leanprover-community#20669). Ubuntu 26.04 and Fedora 44 ship 8.18, so sending them to the static curl would put a self-built binary on most machines, and the static binary cannot find Fedora's CA bundle. The tool now keeps the system curl on these versions and omits curl's retry flags. `CurlMode` carries the choice from `validateCurl` to the download pass. The post-build job installs the pinned curl so CI keeps retries after `ubuntu-latest` moves to Ubuntu 26.04. The `cache-get` job on `ubuntu-26.04` checks the retry-free mode.
… 2026/10/CacheGetRetryPass # Conflicts: # Cache/Requests.lean
A parallel pass that curl ends before it reports every transfer counts the gap as failures (leanprover-community#44940), but those failures have no hashes, so the retry pass skipped them and the exit code dropped them. Every file such a pass leaves unserved now joins the retry pass. A miss retried there reads as a miss again.
|
This PR/issue depends on: |
|
This pull request has conflicts, please merge |
…etryPass # Conflicts: # .github/actionlint.yml # .github/workflows/build_template.yml # .github/workflows/cache_test.yml # Cache/CI.md # Cache/IO.lean # Cache/README.md # Cache/Requests.lean # Cache/Test.lean # Cache/Upload/Curl.lean
Give the download curl `--speed-time 30 --speed-limit 1`. A transfer that receives no bytes for 30 s ends with curl exit 28. The retry pass then fetches it in a fresh curl, over a new connection. Without a stall limit, a frozen connection holds `cache get` until the network closes it. A CI job waited 95 minutes on 5 of 9,080 files.
State what each docstring describes: the stall flags, the failed-hash set, the per-location download, the download result, and the two passes. The comment on a curl run that reports fewer transfers than requested says that the round marks the unserved files as failed.
| frozen connection, so we rely on the second download pass in `downloadFiles` to actually | ||
| retry these. -/ | ||
| def curlStallArgs : Array String := | ||
| #["--speed-time", "30", "--speed-limit", "1"] |
There was a problem hiding this comment.
Maybe also include something like --connect-timeout 30 here too to catch hanging connects?
There was a problem hiding this comment.
nice, that makes sense
|
Thanks! |
…resh pass (#45096) `cache get` can lose a few downloads when a transfer stops early, or when a connection freezes and curl waits without a time limit. On 2026-10-27 a frozen connection held a CI job for 95 minutes on 5 of 9,080 files. The download curl runs with `--connect-timeout 30 --speed-time 30 --speed-limit 1`. A connection setup that takes more than 30 s, or a transfer that receives no bytes for 30 s, fails with curl exit 28. curl retries a failed connection setup on a new connection. After the first pass over all cache locations, the tool retries the failed downloads once, in new `curl` processes. curl retries a timed-out transfer on the same connection. The new process of the second pass opens a new connection, which recovers the file. A healthy get has a first-byte time under 1 s, and a slow transfer keeps its bytes flowing, so the limit trips on a frozen connection only. When every transfer fails, the second pass repeats the first, so the time to failure about doubles. Tested against a local proxy that interrupts transfers, and against a local HTTP/2 server that leaves 3 of 94 requests unanswered on the first connection. The tool recovers in both tests and exits 1 when a failure persists. Without the stall flags it hangs in the second test. - [x] depends on: #44940 🤖
|
Pull request successfully merged into master. Build succeeded: |
cache getcan lose a few downloads when a transfer stops early, or when a connection freezes and curl waits without a time limit. On 2026-10-27 a frozen connection held a CI job for 95 minutes on 5 of 9,080 files.The download curl runs with
--connect-timeout 30 --speed-time 30 --speed-limit 1. A connection setup that takes more than 30 s, or a transfer that receives no bytes for 30 s, fails with curl exit 28. curl retries a failed connection setup on a new connection. After the first pass over all cache locations, the tool retries the failed downloads once, in newcurlprocesses. curl retries a timed-out transfer on the same connection. The new process of the second pass opens a new connection, which recovers the file.A healthy get has a first-byte time under 1 s, and a slow transfer keeps its bytes flowing, so the limit trips on a frozen connection only. When every transfer fails, the second pass repeats the first, so the time to failure about doubles.
Tested against a local proxy that interrupts transfers, and against a local HTTP/2 server that leaves 3 of 94 requests unanswered on the first connection. The tool recovers in both tests and exits 1 when a failure persists. Without the stall flags it hangs in the second test.
🤖