Skip to content

Retry transient download failures instead of panicking - #40

Merged
jiegec merged 1 commit into
masterfrom
fix/download-retry-39
Sep 25, 2026
Merged

jiegec merged 1 commit into
masterfrom
fix/download-retry-39

Conversation

@jiegec

@jiegec jiegec commented Sep 24, 2026

Copy link
Copy Markdown
Owner

Fixes the retry part of #39.

What changed

download() now retries transient failures (timeouts, connection resets, truncated bodies, 5xx/429) with exponential backoff, configurable via --retries (default 3). Once the attempts are exhausted it returns a proper error instead of the previous .unwrap() panic at the call sites, so one stalled connection no longer throws away the in-flight progress of the current channel.

Related robustness fixes in the same code path:

  • HTTP status is checked before the body is written, and truncated responses are detected (a short read used to loop forever on a non-zero content-length).
  • Permanent 4xx responses (except 408/429) are not retried, which matters for the many optional rustup-init downloads that legitimately 404.
  • The component SHA-256 mismatch is now a clean error rather than an assert_eq!.
  • main() returns Result, so required downloads propagate errors instead of panicking.

--retries 0 disables retries.

Re: [[artifacts.*]]

Intentional. Those entries (rust-*.msi, rust-*.pkg, rustc-*-src.tar.*) are not used by rustup itself, so they are neither mirrored nor rewritten. Leaving the official URLs in place is correct: rewriting them to the mirror would advertise files the mirror does not serve.

Testing

  • cargo build, cargo test (new unit test for the backoff schedule), cargo fmt --check.
  • cargo clippy clean apart from the pre-existing warning at src/main.rs:378.

A single stalled connection used to abort an entire mirror run because
download() unwrapped its reqwest error at every call site. Retry each
download a few times with exponential backoff (--retries, default 3) and
return a proper error once the attempts are exhausted, so a full sync no
longer has to be wrapped in an external retry loop.

Also make the downloader more robust:

- Check the HTTP status before writing the body and detect truncated
  responses, which previously could spin forever on a short read.
- Do not retry permanent 4xx responses (except 408/429), which matters for
  the many optional rustup-init downloads that legitimately 404.
- Turn the component checksum assertion into a clean error.
- Make main() return Result so required downloads propagate rather than
  panic.

Fixes #39.
@jiegec
jiegec merged commit 923931f into master Sep 25, 2026
1 check passed
@jiegec
jiegec deleted the fix/download-retry-39 branch September 25, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant