mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-04 19:08:04 +00:00
Check nested IO errors for retries (#13260)
## Summary The only thing that changed for #12175 relevant to the existing downloads is the order of nesting, so we're checking all nested IO errors instead of only the first one. See #13238 ## Test Plan This is an educated guess based on what happens if I turn off the network during a download. ``` Downloading cpython-3.13.3-linux-x86_64-gnu (download) (20.3MiB) TRACE Considering retry of error: ExtractError("cpython-3.13.3-20250409-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz", Io(Custom { kind: Other, error: TarError { desc: "failed to unpack `/home/konsti/.local/share/uv/python/.temp/.tmpe3AIvt/python/lib/libpython3.13.so.1.0`", io: Custom { kind: Other, error: TarError { desc: "failed to unpack `python/lib/libpython3.13.so.1.0` into `/home/konsti/.local/share/uv/python/.temp/.tmpe3AIvt/python/lib/libpython3.13.so.1.0`", io: Custom { kind: Other, error: reqwest::Error { kind: Decode, source: reqwest::Error { kind: Body, source: TimedOut } } } } } } })) TRACE Cannot retry IO error: not one of `ConnectionReset` or `UnexpectedEof` TRACE Cannot retry IO error: not one of `ConnectionReset` or `UnexpectedEof` TRACE Cannot retry error: not an IO error error: Failed to install cpython-3.13.3-linux-x86_64-gnu Caused by: Failed to extract archive: cpython-3.13.3-20250409-x86_64-unknown-linux-gnu-install_only_stripped.tar.gz Caused by: failed to unpack `/home/konsti/.local/share/uv/python/.temp/.tmpe3AIvt/python/lib/libpython3.13.so.1.0` Caused by: failed to unpack `python/lib/libpython3.13.so.1.0` into `/home/konsti/.local/share/uv/python/.temp/.tmpe3AIvt/python/lib/libpython3.13.so.1.0` Caused by: error decoding response body Caused by: request or response body error Caused by: operation timed out ```
This commit is contained in:
parent
801fd0e5b8
commit
360a335e7f
1 changed files with 16 additions and 7 deletions
|
@ -4,7 +4,7 @@ use std::fmt::Write;
|
|||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{env, iter};
|
||||
use std::{env, io, iter};
|
||||
|
||||
use itertools::Itertools;
|
||||
use reqwest::{Client, ClientBuilder, Proxy, Response};
|
||||
|
@ -493,18 +493,18 @@ pub fn is_extended_transient_error(err: &dyn Error) -> bool {
|
|||
trace!("Considering retry of error: {err:?}");
|
||||
}
|
||||
|
||||
if let Some(io) = find_source::<std::io::Error>(&err) {
|
||||
if io.kind() == std::io::ErrorKind::ConnectionReset
|
||||
|| io.kind() == std::io::ErrorKind::UnexpectedEof
|
||||
// IO Errors may be nested through custom IO errors.
|
||||
for io_err in find_sources::<io::Error>(&err) {
|
||||
if io_err.kind() == io::ErrorKind::ConnectionReset
|
||||
|| io_err.kind() == io::ErrorKind::UnexpectedEof
|
||||
{
|
||||
trace!("Retrying error: `ConnectionReset` or `UnexpectedEof`");
|
||||
return true;
|
||||
}
|
||||
trace!("Cannot retry error: not one of `ConnectionReset` or `UnexpectedEof`");
|
||||
} else {
|
||||
trace!("Cannot retry error: not an IO error");
|
||||
trace!("Cannot retry IO error: not one of `ConnectionReset` or `UnexpectedEof`");
|
||||
}
|
||||
|
||||
trace!("Cannot retry error: not an IO error");
|
||||
false
|
||||
}
|
||||
|
||||
|
@ -521,3 +521,12 @@ fn find_source<E: Error + 'static>(orig: &dyn Error) -> Option<&E> {
|
|||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Return all errors in the chain of a specific type.
|
||||
///
|
||||
/// This handles cases such as nested `io::Error`s.
|
||||
///
|
||||
/// See <https://github.com/seanmonstar/reqwest/issues/1602#issuecomment-1220996681>
|
||||
fn find_sources<E: Error + 'static>(orig: &dyn Error) -> impl Iterator<Item = &E> {
|
||||
iter::successors(find_source::<E>(orig), |&err| find_source(err))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue