Log the duration we took before erroring (#18231)
We previously errored due to not having long enough backoff, and there were questions about how long the retries are, so let's log this on failure.
This commit is contained in:
@@ -8,6 +8,7 @@ use std::path::PathBuf;
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::{Duration, SystemTimeError};
|
||||
|
||||
use futures::{StreamExt, TryStreamExt};
|
||||
use reqwest_retry::policies::ExponentialBackoff;
|
||||
@@ -248,11 +249,16 @@ pub enum Error {
|
||||
#[error("Failed to detect platform")]
|
||||
Platform(#[from] uv_platform::Error),
|
||||
|
||||
#[error("Request failed after {retries} {subject}", subject = if *retries > 1 { "retries" } else { "retry" })]
|
||||
#[error(
|
||||
"Request failed after {retries} {subject} in {duration:.1}s",
|
||||
subject = if *retries > 1 { "retries" } else { "retry" },
|
||||
duration = duration.as_secs_f32()
|
||||
)]
|
||||
RetriedError {
|
||||
#[source]
|
||||
err: Box<Self>,
|
||||
retries: u32,
|
||||
duration: Duration,
|
||||
},
|
||||
|
||||
#[error("Failed to fetch version manifest from: {url}")]
|
||||
@@ -287,6 +293,9 @@ pub enum Error {
|
||||
|
||||
#[error("Unsupported archive format: {0}")]
|
||||
UnsupportedArchiveFormat(String),
|
||||
|
||||
#[error(transparent)]
|
||||
SystemTime(#[from] SystemTimeError),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@@ -352,6 +361,7 @@ pub async fn find_matching_version(
|
||||
Err(Error::RetriedError {
|
||||
err: Box::new(err),
|
||||
retries: retry_state.total_retries(),
|
||||
duration: retry_state.duration()?,
|
||||
})
|
||||
} else {
|
||||
Err(err)
|
||||
@@ -628,6 +638,7 @@ async fn download_and_unpack_with_retry(
|
||||
Err(Error::RetriedError {
|
||||
err: Box::new(err),
|
||||
retries: retry_state.total_retries(),
|
||||
duration: retry_state.duration()?,
|
||||
})
|
||||
} else {
|
||||
Err(err)
|
||||
@@ -678,6 +689,8 @@ async fn download_and_unpack(
|
||||
return Err(Error::RetriedError {
|
||||
err: Box::new(err),
|
||||
retries,
|
||||
// This value is overwritten in `download_and_unpack_with_retry`.
|
||||
duration: Duration::default(),
|
||||
});
|
||||
}
|
||||
return Err(err);
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::fmt::Write;
|
||||
use std::num::ParseIntError;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::time::{Duration, SystemTime, SystemTimeError};
|
||||
use std::{env, io, iter};
|
||||
|
||||
use anyhow::anyhow;
|
||||
@@ -1317,6 +1317,11 @@ impl RetryState {
|
||||
self.total_retries
|
||||
}
|
||||
|
||||
/// The total duration from the first request to the (failure) of the last request.
|
||||
pub fn duration(&self) -> Result<Duration, SystemTimeError> {
|
||||
self.start_time.elapsed()
|
||||
}
|
||||
|
||||
/// Determines whether request should be retried.
|
||||
///
|
||||
/// Takes the number of retries from nested layers associated with the specific `err` type as
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{borrow::Cow, path::Path};
|
||||
|
||||
use futures::FutureExt;
|
||||
@@ -105,7 +106,11 @@ pub enum CachedClientError<CallbackError: std::error::Error + 'static> {
|
||||
Client(Error),
|
||||
/// Track retries before a callback explicitly, as we can't attach them to the callback error
|
||||
/// type.
|
||||
Callback { retries: u32, err: CallbackError },
|
||||
Callback {
|
||||
retries: u32,
|
||||
err: CallbackError,
|
||||
duration: Duration,
|
||||
},
|
||||
}
|
||||
|
||||
impl<CallbackError: std::error::Error + 'static> CachedClientError<CallbackError> {
|
||||
@@ -113,7 +118,15 @@ impl<CallbackError: std::error::Error + 'static> CachedClientError<CallbackError
|
||||
fn with_retries(self, retries: u32) -> Self {
|
||||
match self {
|
||||
Self::Client(err) => Self::Client(err.with_retries(retries)),
|
||||
Self::Callback { retries: _, err } => Self::Callback { retries, err },
|
||||
Self::Callback {
|
||||
retries: _,
|
||||
err,
|
||||
duration,
|
||||
} => Self::Callback {
|
||||
retries,
|
||||
err,
|
||||
duration,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,9 +164,11 @@ impl<E: Into<Self> + std::error::Error + 'static> From<CachedClientError<E>> for
|
||||
fn from(error: CachedClientError<E>) -> Self {
|
||||
match error {
|
||||
CachedClientError::Client(error) => error,
|
||||
CachedClientError::Callback { retries, err } => {
|
||||
Self::new(err.into().into_kind(), retries)
|
||||
}
|
||||
CachedClientError::Callback {
|
||||
retries,
|
||||
err,
|
||||
duration,
|
||||
} => Self::new(err.into().into_kind(), retries, duration),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,6 +276,7 @@ impl CachedClient {
|
||||
response_callback: Callback,
|
||||
) -> Result<Payload::Target, CachedClientError<CallBackError>> {
|
||||
let fresh_req = req.try_clone().expect("HTTP request must be cloneable");
|
||||
let start = Instant::now();
|
||||
let cached_response = if let Some(cached) = Self::read_cache(cache_entry).await {
|
||||
self.send_cached(req, cache_control, cached)
|
||||
.boxed_local()
|
||||
@@ -339,6 +355,7 @@ impl CachedClient {
|
||||
self.run_response_callback(
|
||||
cache_entry,
|
||||
cache_policy,
|
||||
start,
|
||||
response,
|
||||
response_callback,
|
||||
)
|
||||
@@ -360,10 +377,11 @@ impl CachedClient {
|
||||
cache_control: CacheControl<'_>,
|
||||
response_callback: Callback,
|
||||
) -> Result<Payload, CachedClientError<CallBackError>> {
|
||||
let start = Instant::now();
|
||||
let (response, cache_policy) = self.fresh_request(req, cache_control).await?;
|
||||
|
||||
let payload = self
|
||||
.run_response_callback(cache_entry, cache_policy, response, async |resp| {
|
||||
.run_response_callback(cache_entry, cache_policy, start, response, async |resp| {
|
||||
let payload = response_callback(resp).await?;
|
||||
Ok(SerdeCacheable { inner: payload })
|
||||
})
|
||||
@@ -384,9 +402,16 @@ impl CachedClient {
|
||||
response_callback: Callback,
|
||||
) -> Result<Payload::Target, CachedClientError<CallBackError>> {
|
||||
let _ = fs_err::tokio::remove_file(&cache_entry.path()).await;
|
||||
let start = Instant::now();
|
||||
let (response, cache_policy) = self.fresh_request(req, cache_control).await?;
|
||||
self.run_response_callback(cache_entry, cache_policy, response, response_callback)
|
||||
.await
|
||||
self.run_response_callback(
|
||||
cache_entry,
|
||||
cache_policy,
|
||||
start,
|
||||
response,
|
||||
response_callback,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
async fn run_response_callback<
|
||||
@@ -397,6 +422,7 @@ impl CachedClient {
|
||||
&self,
|
||||
cache_entry: &CacheEntry,
|
||||
cache_policy: Option<Box<CachePolicy>>,
|
||||
start: Instant,
|
||||
response: Response,
|
||||
response_callback: Callback,
|
||||
) -> Result<Payload::Target, CachedClientError<CallBackError>> {
|
||||
@@ -410,7 +436,11 @@ impl CachedClient {
|
||||
let data = response_callback(response)
|
||||
.boxed_local()
|
||||
.await
|
||||
.map_err(|err| CachedClientError::Callback { retries, err })?;
|
||||
.map_err(|err| CachedClientError::Callback {
|
||||
retries,
|
||||
err,
|
||||
duration: start.elapsed(),
|
||||
})?;
|
||||
let Some(cache_policy) = cache_policy else {
|
||||
return Ok(data.into_target());
|
||||
};
|
||||
@@ -516,12 +546,13 @@ impl CachedClient {
|
||||
) -> Result<CachedResponse, Error> {
|
||||
let url = DisplaySafeUrl::from_url(req.url().clone());
|
||||
debug!("Sending revalidation request for: {url}");
|
||||
let start = Instant::now();
|
||||
let mut response = self
|
||||
.0
|
||||
.execute(req)
|
||||
.instrument(info_span!("revalidation_request", url = url.as_str()))
|
||||
.await
|
||||
.map_err(|err| Error::from_reqwest_middleware(url.clone(), err))?;
|
||||
.map_err(|err| Error::from_reqwest_middleware(url.clone(), err, start))?;
|
||||
trace!(
|
||||
"Received response for revalidation request with status {} for: {}",
|
||||
response.status(),
|
||||
@@ -581,11 +612,12 @@ impl CachedClient {
|
||||
let url = DisplaySafeUrl::from_url(req.url().clone());
|
||||
debug!("Sending fresh {} request for: {}", req.method(), url);
|
||||
let cache_policy_builder = CachePolicyBuilder::new(&req);
|
||||
let start = Instant::now();
|
||||
let mut response = self
|
||||
.0
|
||||
.execute(req)
|
||||
.await
|
||||
.map_err(|err| Error::from_reqwest_middleware(url.clone(), err))?;
|
||||
.map_err(|err| Error::from_reqwest_middleware(url.clone(), err, start))?;
|
||||
trace!(
|
||||
"Received response for fresh request with status {} for: {}",
|
||||
response.status(),
|
||||
@@ -611,6 +643,7 @@ impl CachedClient {
|
||||
return Err(Error::new(
|
||||
ErrorKind::from_reqwest_with_problem_details(url, status_error, problem_details),
|
||||
retry_count.unwrap_or_default(),
|
||||
start.elapsed(),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use async_http_range_reader::AsyncHttpRangeReaderError;
|
||||
use async_zip::error::ZipError;
|
||||
use reqwest::Response;
|
||||
use serde::Deserialize;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use tracing::warn;
|
||||
|
||||
use uv_cache::Error as CacheError;
|
||||
@@ -114,6 +116,7 @@ impl ProblemDetails {
|
||||
pub struct Error {
|
||||
kind: Box<ErrorKind>,
|
||||
retries: u32,
|
||||
duration: Duration,
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
@@ -121,9 +124,10 @@ impl Display for Error {
|
||||
if self.retries > 0 {
|
||||
write!(
|
||||
f,
|
||||
"Request failed after {retries} {subject}",
|
||||
"Request failed after {retries} {subject} in {duration:.1}s",
|
||||
retries = self.retries,
|
||||
subject = if self.retries > 1 { "retries" } else { "retry" }
|
||||
subject = if self.retries > 1 { "retries" } else { "retry" },
|
||||
duration = self.duration.as_secs_f32(),
|
||||
)
|
||||
} else {
|
||||
Display::fmt(&self.kind, f)
|
||||
@@ -143,10 +147,11 @@ impl std::error::Error for Error {
|
||||
|
||||
impl Error {
|
||||
/// Create a new [`Error`] with the given [`ErrorKind`] and number of retries.
|
||||
pub fn new(kind: ErrorKind, retries: u32) -> Self {
|
||||
pub fn new(kind: ErrorKind, retries: u32, duration: Duration) -> Self {
|
||||
Self {
|
||||
kind: Box::new(kind),
|
||||
retries,
|
||||
duration,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,6 +160,12 @@ impl Error {
|
||||
self.retries
|
||||
}
|
||||
|
||||
/// Return the time taken for network requests, including retries, backoff and jitter,
|
||||
/// before this error was returned.
|
||||
pub fn duration(&self) -> Duration {
|
||||
self.duration
|
||||
}
|
||||
|
||||
/// Convert this error into an [`ErrorKind`].
|
||||
pub fn into_kind(self) -> ErrorKind {
|
||||
*self.kind
|
||||
@@ -189,6 +200,7 @@ impl Error {
|
||||
pub(crate) fn from_reqwest_middleware(
|
||||
url: DisplaySafeUrl,
|
||||
err: reqwest_middleware::Error,
|
||||
start: Instant,
|
||||
) -> Self {
|
||||
if let reqwest_middleware::Error::Middleware(ref underlying) = err {
|
||||
if let Some(offline_err) = underlying.downcast_ref::<OfflineError>() {
|
||||
@@ -201,6 +213,7 @@ impl Error {
|
||||
return Self::new(
|
||||
ErrorKind::WrappedReqwestError(url, WrappedReqwestError::from(err)),
|
||||
retries,
|
||||
start.elapsed(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -316,6 +329,7 @@ impl From<ErrorKind> for Error {
|
||||
Self {
|
||||
kind: Box::new(kind),
|
||||
retries: 0,
|
||||
duration: Duration::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use std::path::{Path, PathBuf};
|
||||
use std::pin::Pin;
|
||||
use std::str::FromStr;
|
||||
use std::task::{Context, Poll};
|
||||
use std::time::{Duration, Instant, SystemTimeError};
|
||||
use std::{env, io};
|
||||
|
||||
use futures::TryStreamExt;
|
||||
@@ -54,11 +55,16 @@ pub enum Error {
|
||||
TooManyParts(String),
|
||||
#[error("Failed to download {0}")]
|
||||
NetworkError(DisplaySafeUrl, #[source] WrappedReqwestError),
|
||||
#[error("Request failed after {retries} {subject}", subject = if *retries > 1 { "retries" } else { "retry" })]
|
||||
#[error(
|
||||
"Request failed after {retries} {subject} in {duration:.1}s",
|
||||
subject = if *retries > 1 { "retries" } else { "retry" },
|
||||
duration = duration.as_secs_f32()
|
||||
)]
|
||||
NetworkErrorWithRetries {
|
||||
#[source]
|
||||
err: Box<Self>,
|
||||
retries: u32,
|
||||
duration: Duration,
|
||||
},
|
||||
#[error("Failed to download {0}")]
|
||||
NetworkMiddlewareError(DisplaySafeUrl, #[source] anyhow::Error),
|
||||
@@ -116,6 +122,8 @@ pub enum Error {
|
||||
BuildVersion(#[from] BuildVersionError),
|
||||
#[error("No download URL found for Python")]
|
||||
NoPythonDownloadUrlFound,
|
||||
#[error(transparent)]
|
||||
SystemTime(#[from] SystemTimeError),
|
||||
}
|
||||
|
||||
impl Error {
|
||||
@@ -1183,6 +1191,7 @@ impl ManagedPythonDownload {
|
||||
Err(Error::NetworkErrorWithRetries {
|
||||
err: Box::new(err),
|
||||
retries: retry_state.total_retries(),
|
||||
duration: retry_state.duration()?,
|
||||
})
|
||||
} else {
|
||||
Err(err)
|
||||
@@ -1698,12 +1707,14 @@ impl Error {
|
||||
url: DisplaySafeUrl,
|
||||
err: reqwest::Error,
|
||||
retries: Option<u32>,
|
||||
start: Instant,
|
||||
) -> Self {
|
||||
let err = Self::NetworkError(url, WrappedReqwestError::from(err));
|
||||
if let Some(retries) = retries {
|
||||
Self::NetworkErrorWithRetries {
|
||||
err: Box::new(err),
|
||||
retries,
|
||||
duration: start.elapsed(),
|
||||
}
|
||||
} else {
|
||||
err
|
||||
@@ -1815,6 +1826,7 @@ async fn read_url(
|
||||
|
||||
Ok((Either::Left(reader), Some(size)))
|
||||
} else {
|
||||
let start = Instant::now();
|
||||
let response = client
|
||||
.for_host(url)
|
||||
.get(Url::from(url.clone()))
|
||||
@@ -1830,7 +1842,7 @@ async fn read_url(
|
||||
// Check the status code.
|
||||
let response = response
|
||||
.error_for_status()
|
||||
.map_err(|err| Error::from_reqwest(url.clone(), err, retry_count))?;
|
||||
.map_err(|err| Error::from_reqwest(url.clone(), err, retry_count, start))?;
|
||||
|
||||
let size = response.content_length();
|
||||
let stream = response
|
||||
|
||||
@@ -248,6 +248,7 @@ impl<Context: BuildContext> ResolverProvider for DefaultResolverProvider<'_, Con
|
||||
Err(err) => match err {
|
||||
uv_distribution::Error::Client(client) => {
|
||||
let retries = client.retries();
|
||||
let duration = client.duration();
|
||||
match client.into_kind() {
|
||||
uv_client::ErrorKind::Offline(_) => {
|
||||
Ok(MetadataResponse::Unavailable(MetadataUnavailable::Offline))
|
||||
@@ -262,7 +263,7 @@ impl<Context: BuildContext> ResolverProvider for DefaultResolverProvider<'_, Con
|
||||
MetadataUnavailable::InvalidStructure(Arc::new(err)),
|
||||
))
|
||||
}
|
||||
kind => Err(uv_client::Error::new(kind, retries).into()),
|
||||
kind => Err(uv_client::Error::new(kind, retries, duration).into()),
|
||||
}
|
||||
}
|
||||
uv_distribution::Error::WheelMetadataVersionMismatch { .. } => {
|
||||
|
||||
@@ -13321,13 +13321,14 @@ async fn add_unexpected_error_code() -> Result<()> {
|
||||
})?;
|
||||
|
||||
uv_snapshot!(context.filters(), context.add().arg("anyio").arg("--index").arg(server.uri())
|
||||
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true"), @"
|
||||
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true")
|
||||
.env(EnvVars::UV_HTTP_RETRIES, "1"), @"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Request failed after 3 retries
|
||||
error: Request failed after 1 retry in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/anyio/`
|
||||
Caused by: HTTP status server error (503 Service Unavailable) for url (http://[LOCALHOST]/anyio/)
|
||||
"
|
||||
|
||||
@@ -240,8 +240,7 @@ async fn simple_http_500() {
|
||||
|
||||
let (_server_drop_guard, mock_server_uri) = http_error_server().await;
|
||||
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg("tqdm")
|
||||
.arg("--index-url")
|
||||
@@ -252,9 +251,9 @@ async fn simple_http_500() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Request failed after 3 retries
|
||||
Caused by: Failed to fetch: `[SERVER]/tqdm/`
|
||||
Caused by: HTTP status server error (500 Internal Server Error) for url ([SERVER]/tqdm/)
|
||||
error: Request failed after 3 retries in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/tqdm/`
|
||||
Caused by: HTTP status server error (500 Internal Server Error) for url (http://[LOCALHOST]/tqdm/)
|
||||
");
|
||||
}
|
||||
|
||||
@@ -265,8 +264,7 @@ async fn simple_io_err() {
|
||||
|
||||
let (_server_drop_guard, mock_server_uri) = io_error_server().await;
|
||||
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg("tqdm")
|
||||
.arg("--index-url")
|
||||
@@ -277,9 +275,9 @@ async fn simple_io_err() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Request failed after 3 retries
|
||||
Caused by: Failed to fetch: `[SERVER]/tqdm/`
|
||||
Caused by: error sending request for url ([SERVER]/tqdm/)
|
||||
error: Request failed after 3 retries in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/tqdm/`
|
||||
Caused by: error sending request for url (http://[LOCALHOST]/tqdm/)
|
||||
Caused by: client error (SendRequest)
|
||||
Caused by: connection closed before message completed
|
||||
");
|
||||
@@ -292,8 +290,7 @@ async fn find_links_http_500() {
|
||||
|
||||
let (_server_drop_guard, mock_server_uri) = http_error_server().await;
|
||||
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg("tqdm")
|
||||
.arg("--no-index")
|
||||
@@ -305,10 +302,10 @@ async fn find_links_http_500() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to read `--find-links` URL: [SERVER]/
|
||||
Caused by: Request failed after 3 retries
|
||||
Caused by: Failed to fetch: `[SERVER]/`
|
||||
Caused by: HTTP status server error (500 Internal Server Error) for url ([SERVER]/)
|
||||
error: Failed to read `--find-links` URL: http://[LOCALHOST]/
|
||||
Caused by: Request failed after 3 retries in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/`
|
||||
Caused by: HTTP status server error (500 Internal Server Error) for url (http://[LOCALHOST]/)
|
||||
");
|
||||
}
|
||||
|
||||
@@ -319,8 +316,7 @@ async fn find_links_io_error() {
|
||||
|
||||
let (_server_drop_guard, mock_server_uri) = io_error_server().await;
|
||||
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg("tqdm")
|
||||
.arg("--no-index")
|
||||
@@ -332,10 +328,10 @@ async fn find_links_io_error() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to read `--find-links` URL: [SERVER]/
|
||||
Caused by: Request failed after 3 retries
|
||||
Caused by: Failed to fetch: `[SERVER]/`
|
||||
Caused by: error sending request for url ([SERVER]/)
|
||||
error: Failed to read `--find-links` URL: http://[LOCALHOST]/
|
||||
Caused by: Request failed after 3 retries in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/`
|
||||
Caused by: error sending request for url (http://[LOCALHOST]/)
|
||||
Caused by: client error (SendRequest)
|
||||
Caused by: connection closed before message completed
|
||||
");
|
||||
@@ -349,8 +345,7 @@ async fn find_links_mixed_error() {
|
||||
|
||||
let (_server_drop_guard, mock_server_uri) = mixed_error_server().await;
|
||||
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg("tqdm")
|
||||
.arg("--no-index")
|
||||
@@ -362,10 +357,10 @@ async fn find_links_mixed_error() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to read `--find-links` URL: [SERVER]/
|
||||
Caused by: Request failed after 3 retries
|
||||
Caused by: Failed to fetch: `[SERVER]/`
|
||||
Caused by: HTTP status server error (500 Internal Server Error) for url ([SERVER]/)
|
||||
error: Failed to read `--find-links` URL: http://[LOCALHOST]/
|
||||
Caused by: Request failed after 3 retries in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/`
|
||||
Caused by: HTTP status server error (500 Internal Server Error) for url (http://[LOCALHOST]/)
|
||||
");
|
||||
}
|
||||
|
||||
@@ -380,8 +375,7 @@ async fn direct_url_http_500() {
|
||||
let tqdm_url = format!(
|
||||
"{mock_server_uri}/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl"
|
||||
);
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg(format!("tqdm @ {tqdm_url}"))
|
||||
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true"), @"
|
||||
@@ -390,10 +384,10 @@ async fn direct_url_http_500() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× Failed to download `tqdm @ [SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Request failed after 3 retries
|
||||
├─▶ Failed to fetch: `[SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
╰─▶ HTTP status server error (500 Internal Server Error) for url ([SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl)
|
||||
× Failed to download `tqdm @ http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Request failed after 3 retries in [TIME]
|
||||
├─▶ Failed to fetch: `http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
╰─▶ HTTP status server error (500 Internal Server Error) for url (http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl)
|
||||
");
|
||||
}
|
||||
|
||||
@@ -407,8 +401,7 @@ async fn direct_url_io_error() {
|
||||
let tqdm_url = format!(
|
||||
"{mock_server_uri}/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl"
|
||||
);
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg(format!("tqdm @ {tqdm_url}"))
|
||||
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true"), @"
|
||||
@@ -417,10 +410,10 @@ async fn direct_url_io_error() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× Failed to download `tqdm @ [SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Request failed after 3 retries
|
||||
├─▶ Failed to fetch: `[SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ error sending request for url ([SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl)
|
||||
× Failed to download `tqdm @ http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Request failed after 3 retries in [TIME]
|
||||
├─▶ Failed to fetch: `http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ error sending request for url (http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl)
|
||||
├─▶ client error (SendRequest)
|
||||
╰─▶ connection closed before message completed
|
||||
");
|
||||
@@ -437,8 +430,7 @@ async fn direct_url_mixed_error() {
|
||||
let tqdm_url = format!(
|
||||
"{mock_server_uri}/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl"
|
||||
);
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg(format!("tqdm @ {tqdm_url}"))
|
||||
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true"), @"
|
||||
@@ -447,10 +439,10 @@ async fn direct_url_mixed_error() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× Failed to download `tqdm @ [SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Request failed after 3 retries
|
||||
├─▶ Failed to fetch: `[SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
╰─▶ HTTP status server error (500 Internal Server Error) for url ([SERVER]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl)
|
||||
× Failed to download `tqdm @ http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Request failed after 3 retries in [TIME]
|
||||
├─▶ Failed to fetch: `http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl`
|
||||
╰─▶ HTTP status server error (500 Internal Server Error) for url (http://[LOCALHOST]/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl)
|
||||
");
|
||||
}
|
||||
|
||||
@@ -493,8 +485,7 @@ async fn python_install_http_500() {
|
||||
|
||||
let python_downloads_json = write_python_downloads_json(&context, &mock_server_uri);
|
||||
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.python_install()
|
||||
.arg("cpython-3.10.0-darwin-aarch64-none")
|
||||
.arg("--python-downloads-json-url")
|
||||
@@ -505,10 +496,10 @@ async fn python_install_http_500() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to install cpython-3.10.0-macos-aarch64-none
|
||||
Caused by: Request failed after 3 retries
|
||||
Caused by: Failed to download [SERVER]/astral-sh/python-build-standalone/releases/download/20211017/cpython-3.10.0-aarch64-apple-darwin-pgo%2Blto-20211017T1616.tar.zst
|
||||
Caused by: HTTP status server error (500 Internal Server Error) for url ([SERVER]/astral-sh/python-build-standalone/releases/download/20211017/cpython-3.10.0-aarch64-apple-darwin-pgo%2Blto-20211017T1616.tar.zst)
|
||||
error: Failed to install cpython-3.10.0-[PLATFORM]
|
||||
Caused by: Request failed after 3 retries in [TIME]
|
||||
Caused by: Failed to download http://[LOCALHOST]/astral-sh/python-build-standalone/releases/download/20211017/cpython-3.10.0-[PLATFORM]-pgo%2Blto-20211017T1616.tar.zst
|
||||
Caused by: HTTP status server error (500 Internal Server Error) for url (http://[LOCALHOST]/astral-sh/python-build-standalone/releases/download/20211017/cpython-3.10.0-[PLATFORM]-pgo%2Blto-20211017T1616.tar.zst)
|
||||
");
|
||||
}
|
||||
|
||||
@@ -524,8 +515,7 @@ async fn python_install_io_error() {
|
||||
|
||||
let python_downloads_json = write_python_downloads_json(&context, &mock_server_uri);
|
||||
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.python_install()
|
||||
.arg("cpython-3.10.0-darwin-aarch64-none")
|
||||
.arg("--python-downloads-json-url")
|
||||
@@ -536,10 +526,10 @@ async fn python_install_io_error() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to install cpython-3.10.0-macos-aarch64-none
|
||||
Caused by: Request failed after 3 retries
|
||||
Caused by: Failed to download [SERVER]/astral-sh/python-build-standalone/releases/download/20211017/cpython-3.10.0-aarch64-apple-darwin-pgo%2Blto-20211017T1616.tar.zst
|
||||
Caused by: error sending request for url ([SERVER]/astral-sh/python-build-standalone/releases/download/20211017/cpython-3.10.0-aarch64-apple-darwin-pgo%2Blto-20211017T1616.tar.zst)
|
||||
error: Failed to install cpython-3.10.0-[PLATFORM]
|
||||
Caused by: Request failed after 3 retries in [TIME]
|
||||
Caused by: Failed to download http://[LOCALHOST]/astral-sh/python-build-standalone/releases/download/20211017/cpython-3.10.0-[PLATFORM]-pgo%2Blto-20211017T1616.tar.zst
|
||||
Caused by: error sending request for url (http://[LOCALHOST]/astral-sh/python-build-standalone/releases/download/20211017/cpython-3.10.0-[PLATFORM]-pgo%2Blto-20211017T1616.tar.zst)
|
||||
Caused by: client error (SendRequest)
|
||||
Caused by: connection closed before message completed
|
||||
");
|
||||
@@ -611,7 +601,7 @@ async fn install_http_retries() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Request failed after 5 retries
|
||||
error: Request failed after 5 retries in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/anyio/`
|
||||
Caused by: HTTP status server error (503 Service Unavailable) for url (http://[LOCALHOST]/anyio/)
|
||||
"
|
||||
@@ -643,7 +633,7 @@ async fn install_http_retry_low_level() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Request failed after 1 retry
|
||||
error: Request failed after 1 retry in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/anyio/`
|
||||
Caused by: error sending request for url (http://[LOCALHOST]/anyio/)
|
||||
Caused by: client error (SendRequest)
|
||||
@@ -684,8 +674,7 @@ async fn rfc9457_problem_details_license_violation() {
|
||||
let mock_server_uri = server.uri();
|
||||
let tqdm_url = format!("{mock_server_uri}/packages/tqdm-4.67.1-py3-none-any.whl");
|
||||
|
||||
let filters = vec![(mock_server_uri.as_str(), "[SERVER]")];
|
||||
uv_snapshot!(filters, context
|
||||
uv_snapshot!(context.filters(), context
|
||||
.pip_install()
|
||||
.arg(format!("tqdm @ {tqdm_url}")), @"
|
||||
success: false
|
||||
@@ -693,10 +682,10 @@ async fn rfc9457_problem_details_license_violation() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× Failed to download `tqdm @ [SERVER]/packages/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Failed to fetch: `[SERVER]/packages/tqdm-4.67.1-py3-none-any.whl`
|
||||
× Failed to download `tqdm @ http://[LOCALHOST]/packages/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Failed to fetch: `http://[LOCALHOST]/packages/tqdm-4.67.1-py3-none-any.whl`
|
||||
├─▶ Server message: License Compliance Issue, This package version has a license that violates organizational policy.
|
||||
╰─▶ HTTP status client error (403 Forbidden) for url ([SERVER]/packages/tqdm-4.67.1-py3-none-any.whl)
|
||||
╰─▶ HTTP status client error (403 Forbidden) for url (http://[LOCALHOST]/packages/tqdm-4.67.1-py3-none-any.whl)
|
||||
");
|
||||
}
|
||||
|
||||
@@ -1079,7 +1068,7 @@ async fn retry_read_timeout_index() {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Request failed after 1 retry
|
||||
error: Request failed after 1 retry in [TIME]
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/tqdm/`
|
||||
Caused by: error decoding response body
|
||||
Caused by: request or response body error
|
||||
@@ -1105,7 +1094,7 @@ async fn retry_read_timeout_stream() {
|
||||
|
||||
----- stderr -----
|
||||
× Failed to download `tqdm @ http://[LOCALHOST]/tqdm-0.1-py3-none-any.whl`
|
||||
├─▶ Request failed after 1 retry
|
||||
├─▶ Request failed after 1 retry in [TIME]
|
||||
├─▶ Failed to read metadata: `http://[LOCALHOST]/tqdm-0.1-py3-none-any.whl`
|
||||
├─▶ Failed to read from zip file
|
||||
├─▶ an upstream reader returned an error: Failed to download distribution due to network timeout. Try increasing UV_HTTP_TIMEOUT (current value: [TIME]).
|
||||
|
||||
@@ -14326,7 +14326,7 @@ fn warn_on_lzma_wheel() {
|
||||
|
||||
----- stderr -----
|
||||
× Failed to download `futzed-lzma @ https://github.com/astral-sh/futzed-wheels/releases/download/v2026.02.09.2/futzed_lzma-0.1.0-py3-none-any.whl`
|
||||
├─▶ Request failed after 3 retries
|
||||
├─▶ Request failed after 3 retries in [TIME]
|
||||
├─▶ Failed to read metadata: `https://github.com/astral-sh/futzed-wheels/releases/download/v2026.02.09.2/futzed_lzma-0.1.0-py3-none-any.whl`
|
||||
├─▶ Failed to read from zip file
|
||||
├─▶ an upstream reader returned an error: stream/file format not recognized
|
||||
|
||||
Reference in New Issue
Block a user