mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Download wheel to disk when streaming unzip failed with HTTP streaming error (#5094)
## Summary
Workaround the `stream_wheel` not retry issue
[found](https://github.com/astral-sh/uv/issues/3514#issuecomment-2229820667)
in #3514, it's not a perfect solution but I think it's acceptable
because the error should not occur frequently.
## Test Plan
Manually using `iptables -A OUTPUT -p tcp -dport 3128 -j REJECT
--reject-with tcp-reset` to inject connection reset error to the HTTP
proxy that proxies PyPI requests.
```
error: Failed to prepare distributions
Caused by: Failed to fetch wheel: piqp==0.4.1
Caused by: Request failed after 3 retries
Caused by: error sending request for url (09ade94dfd/piqp-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
)
Caused by: client error (Connect)
Caused by: tcp connect error: Connection refused (os error 111)
Caused by: Connection refused (os error 111)
```
This commit is contained in:
parent
545bbf9286
commit
38504dcaee
4 changed files with 27 additions and 4 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -4804,6 +4804,7 @@ dependencies = [
|
||||||
"md-5",
|
"md-5",
|
||||||
"pypi-types",
|
"pypi-types",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"reqwest",
|
||||||
"rustc-hash 2.0.0",
|
"rustc-hash 2.0.0",
|
||||||
"sha2",
|
"sha2",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|
|
@ -208,10 +208,16 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> {
|
||||||
hashes: archive.hashes,
|
hashes: archive.hashes,
|
||||||
filename: wheel.filename.clone(),
|
filename: wheel.filename.clone(),
|
||||||
}),
|
}),
|
||||||
Err(Error::Extract(err)) if err.is_http_streaming_unsupported() => {
|
Err(Error::Extract(err)) => {
|
||||||
|
if err.is_http_streaming_unsupported() {
|
||||||
warn!(
|
warn!(
|
||||||
"Streaming unsupported for {dist}; downloading wheel to disk ({err})"
|
"Streaming unsupported for {dist}; downloading wheel to disk ({err})"
|
||||||
);
|
);
|
||||||
|
} else if err.is_http_streaming_failed() {
|
||||||
|
warn!("Streaming failed for {dist}; downloading wheel to disk ({err})");
|
||||||
|
} else {
|
||||||
|
return Err(Error::Extract(err));
|
||||||
|
}
|
||||||
|
|
||||||
// If the request failed because streaming is unsupported, download the
|
// If the request failed because streaming is unsupported, download the
|
||||||
// wheel directly.
|
// wheel directly.
|
||||||
|
|
|
@ -21,6 +21,7 @@ fs-err = { workspace = true, features = ["tokio"] }
|
||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
md-5.workspace = true
|
md-5.workspace = true
|
||||||
rayon = { workspace = true }
|
rayon = { workspace = true }
|
||||||
|
reqwest = { workspace = true }
|
||||||
rustc-hash = { workspace = true }
|
rustc-hash = { workspace = true }
|
||||||
sha2 = { workspace = true }
|
sha2 = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
|
|
@ -28,4 +28,19 @@ impl Error {
|
||||||
Self::AsyncZip(async_zip::error::ZipError::FeatureNotSupported(_))
|
Self::AsyncZip(async_zip::error::ZipError::FeatureNotSupported(_))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the error is due to HTTP streaming request failed.
|
||||||
|
pub fn is_http_streaming_failed(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Self::AsyncZip(async_zip::error::ZipError::UpstreamReadError(_)) => true,
|
||||||
|
Self::Io(err) => {
|
||||||
|
if let Some(inner) = err.get_ref() {
|
||||||
|
inner.downcast_ref::<reqwest::Error>().is_some()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue