-
-
Notifications
You must be signed in to change notification settings - Fork 317
Description
In uv, we want to retry streaming downloads on connection reset errors. These errors are common e.g. in GitHub Actions when downloading e.g. a 20MB file.
Our goal is to have a streaming download-and-unpack. We have a loop in which we try the streaming download-and-unpack, and if it fails, inspect the error chain on whether it looks like a retryable network error (https://github.com/astral-sh/uv/blob/22f80ca00d3f5af7d087154e998c886bbea8cee1/crates/uv-python/src/downloads.rs#L945-L993). This is easy for status code errors, where we get a reqwest::Error
at the top of the error chain, but during the stream, the error may be nested in several layer of other crates involved in the unpacking, see the example error below.
We want to specifically retry io::ErrorKind::ConnectionReset
. But when trying err.downcast_ref::<io::Error>()
we don't get anything, as the h2 error wraps the IO error, which is not apparent from the debug output.
Tar(
TarError {
desc: "failed to unpack `/home/konsti/.local/share/uv/python/.temp/.tmpBHaUXj/python/bin/python3.12`",
io: Custom {
kind: Other,
error: TarError {
desc: "failed to unpack `python/bin/python3.12` into `/home/konsti/.local/share/uv/python/.temp/.tmpBHaUXj/python/bin/python3.12`",
io: Custom {
kind: Other,
error: reqwest::Error {
kind: Decode,
source: reqwest::Error {
kind: Body,
source: Error {
inner: ErrorImpl {
kind: Body,
cause: Some(
Error {
kind: Io(
Kind(
ConnectionReset,
),
),
},
),
},
},
},
},
},
},
},
},
)
I'm also interested in ways to make our transient network error detection (https://github.com/astral-sh/uv/blob/f88aaa8740824b03be36c7ff106a139151452165/crates/uv-client/src/base_client.rs#L983-L1067) more reliable in general, without going through reqwest's error chain.