mirror of
https://github.com/astral-sh/uv
synced 2026-01-21 21:40:11 -05:00
Track retry counts originating from early middleware errors (#17274)
## Summary Fixes #17266. The retry count was getting dropped by `ErrorKind::from_retry_middleware` and `<Error as From<ErrorKind>>::from` so we were doing more retries than we should have. ## Test Plan Added a testcase for the specific error path in the issue. Added an expect to the other retry test too.
This commit is contained in:
committed by
GitHub
parent
6f9fced6c6
commit
df62ee6f4d
@@ -246,9 +246,15 @@ impl Error {
|
||||
|
||||
impl From<ErrorKind> for Error {
|
||||
fn from(kind: ErrorKind) -> Self {
|
||||
Self {
|
||||
kind: Box::new(kind),
|
||||
retries: 0,
|
||||
match kind {
|
||||
ErrorKind::RequestWithRetries { source, retries } => Self {
|
||||
kind: source,
|
||||
retries,
|
||||
},
|
||||
other => Self {
|
||||
kind: Box::new(other),
|
||||
retries: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -391,6 +397,18 @@ impl ErrorKind {
|
||||
if let Some(err) = underlying.downcast_ref::<OfflineError>() {
|
||||
return Self::Offline(err.url().to_string());
|
||||
}
|
||||
if let Some(reqwest_retry::RetryError::WithRetries { retries, .. }) =
|
||||
underlying.downcast_ref::<reqwest_retry::RetryError>()
|
||||
{
|
||||
let retries = *retries;
|
||||
return Self::RequestWithRetries {
|
||||
source: Box::new(Self::WrappedReqwestError(
|
||||
url,
|
||||
WrappedReqwestError::from(err),
|
||||
)),
|
||||
retries,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Self::WrappedReqwestError(url, WrappedReqwestError::from(err))
|
||||
|
||||
@@ -5,7 +5,7 @@ use http::StatusCode;
|
||||
use serde_json::json;
|
||||
use uv_static::EnvVars;
|
||||
use wiremock::matchers::method;
|
||||
use wiremock::{Mock, MockServer, ResponseTemplate};
|
||||
use wiremock::{Mock, MockServer, Request, ResponseTemplate};
|
||||
|
||||
use crate::common::{TestContext, uv_snapshot};
|
||||
|
||||
@@ -392,6 +392,7 @@ async fn install_http_retries() {
|
||||
// Create a server that always fails, so we can see the number of retries used
|
||||
Mock::given(method("GET"))
|
||||
.respond_with(ResponseTemplate::new(503))
|
||||
.expect(6)
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
@@ -455,6 +456,40 @@ async fn install_http_retries() {
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn install_http_retry_low_level() {
|
||||
let context = TestContext::new("3.12");
|
||||
|
||||
let server = MockServer::start().await;
|
||||
|
||||
// Create a server that fails with a more fundamental error so we trigger
|
||||
// earlier error paths
|
||||
Mock::given(method("GET"))
|
||||
.respond_with_err(|_: &'_ Request| io::Error::new(io::ErrorKind::ConnectionReset, "error"))
|
||||
.expect(2)
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
uv_snapshot!(context.filters(), context.pip_install()
|
||||
.arg("anyio")
|
||||
.arg("--index")
|
||||
.arg(server.uri())
|
||||
.env(EnvVars::UV_HTTP_RETRIES, "1")
|
||||
.env(EnvVars::UV_TEST_NO_HTTP_RETRY_DELAY, "true"), @r"
|
||||
success: false
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
error: Request failed after 1 retry
|
||||
Caused by: Failed to fetch: `http://[LOCALHOST]/anyio/`
|
||||
Caused by: error sending request for url (http://[LOCALHOST]/anyio/)
|
||||
Caused by: client error (SendRequest)
|
||||
Caused by: connection closed before message completed
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
/// Test problem details with a 403 error containing license compliance information
|
||||
#[tokio::test]
|
||||
async fn rfc9457_problem_details_license_violation() {
|
||||
|
||||
Reference in New Issue
Block a user