Skip to content

[Merged by Bors] - fix(cache): time out stalled downloads and retry hard failures in a fresh pass - #45096

Closed
marcelolynch wants to merge 39 commits into
leanprover-community:masterfrom
marcelolynch:2026/10/CacheGetRetryPass
Closed

marcelolynch wants to merge 39 commits into
leanprover-community:masterfrom
marcelolynch:2026/10/CacheGetRetryPass

Conversation

@marcelolynch

@marcelolynch marcelolynch commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

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.

🤖

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.
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.
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

PR summary afeb1e2b37

Import changes for modified files

No significant changes to the import graph

Import changes for all files
Files Import difference

Declarations diff (regex)

+ curlStallArgs

You can run this locally as follows
## from your `mathlib4` directory:
git clone https://github.com/leanprover-community/mathlib-ci.git ../mathlib-ci

## summary with just the declaration names:
../mathlib-ci/scripts/pr_summary/declarations_diff.sh <optional_commit>

## more verbose report:
../mathlib-ci/scripts/pr_summary/declarations_diff.sh long <optional_commit>

The doc-module for scripts/pr_summary/declarations_diff.sh in the mathlib-ci repository contains some details about this script.

Declarations diff (Lean)

✅ Lean-aware diff — post-build, computed from the Lean environment (commit afeb1e2).

  • +0 new declarations
  • −0 removed declarations

No declaration differences.


No changes to strong technical debt.
No changes to weak technical debt.

Current commit afeb1e2b37
Reference commit 3aae103a67

This script lives in the mathlib-ci repository. To run it locally, from your mathlib4 directory:

git clone https://github.com/leanprover-community/mathlib-ci.git ../mathlib-ci
../mathlib-ci/scripts/reporting/technical-debt-metrics.py pr_summary
  • The relative value is the weighted sum of the differences with weight given by the inverse of the current value of the statistic.
  • The absolute value is the relative value divided by the total sum of the inverses of the current values (i.e. the weighted average of the differences).

@github-actions github-actions Bot added the CI Modifies the continuous integration setup or other automation label Oct 20, 2026
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.
@mathlib-dependent-issues mathlib-dependent-issues Bot added the blocked-by-other-PR This PR depends on another PR (this label is automatically managed by a bot) label Oct 21, 2026
@mathlib-dependent-issues mathlib-dependent-issues Bot removed the blocked-by-other-PR This PR depends on another PR (this label is automatically managed by a bot) label Oct 21, 2026
@mathlib-dependent-issues

Copy link
Copy Markdown

This PR/issue depends on:

@mathlib-merge-conflicts mathlib-merge-conflicts Bot added the merge-conflict The PR has a merge conflict with master, and needs manual merging. (this label is managed by a bot) label Oct 22, 2026
@mathlib-merge-conflicts

Copy link
Copy Markdown

This pull request has conflicts, please merge master and resolve them.

…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
@github-actions github-actions Bot removed the merge-conflict The PR has a merge conflict with master, and needs manual merging. (this label is managed by a bot) label Oct 22, 2026
@marcelolynch
marcelolynch marked this pull request as ready for review October 23, 2026 18:21
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.
@marcelolynch marcelolynch changed the title fix(cache): retry hard download failures in a fresh pass fix(cache): time out stalled downloads and retry hard failures in a fresh pass Oct 28, 2026
Comment thread Cache/Requests.lean Outdated
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"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also include something like --connect-timeout 30 here too to catch hanging connects?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, that makes sense

@bryangingechen

Copy link
Copy Markdown
Contributor

Thanks!
bors r+

@mathlib-bors mathlib-bors Bot added the ready-to-merge This PR has been sent to bors. label Oct 28, 2026
mathlib-bors Bot pushed a commit that referenced this pull request Oct 28, 2026
…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

🤖
@mathlib-bors mathlib-bors Bot added the bors-staging This PR is currently being built by bors on the staging branch. label Oct 28, 2026
@mathlib-bors

mathlib-bors Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

@mathlib-bors mathlib-bors Bot changed the title fix(cache): time out stalled downloads and retry hard failures in a fresh pass [Merged by Bors] - fix(cache): time out stalled downloads and retry hard failures in a fresh pass Oct 28, 2026
@mathlib-bors mathlib-bors Bot closed this Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bors-staging This PR is currently being built by bors on the staging branch. CI Modifies the continuous integration setup or other automation ready-to-merge This PR has been sent to bors.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants