mirror of https://github.com/astral-sh/uv
Better error handling for `uv publish` (#17096)
* Use `is_transient_network_error` as we do in all other cases, see also https://github.com/astral-sh/uv/pull/16245 * Don't report success in the progress reporter if the upload failed
This commit is contained in:
parent
5a55bbe883
commit
7ad441a0bd
|
|
@ -13,8 +13,8 @@ use itertools::Itertools;
|
||||||
use reqwest::header::AUTHORIZATION;
|
use reqwest::header::AUTHORIZATION;
|
||||||
use reqwest::multipart::Part;
|
use reqwest::multipart::Part;
|
||||||
use reqwest::{Body, Response, StatusCode};
|
use reqwest::{Body, Response, StatusCode};
|
||||||
|
use reqwest_retry::RetryPolicy;
|
||||||
use reqwest_retry::policies::ExponentialBackoff;
|
use reqwest_retry::policies::ExponentialBackoff;
|
||||||
use reqwest_retry::{RetryPolicy, Retryable, RetryableStrategy};
|
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -28,7 +28,7 @@ use uv_auth::{Credentials, PyxTokenStore};
|
||||||
use uv_cache::{Cache, Refresh};
|
use uv_cache::{Cache, Refresh};
|
||||||
use uv_client::{
|
use uv_client::{
|
||||||
BaseClient, MetadataFormat, OwnedArchive, RegistryClientBuilder, RequestBuilder,
|
BaseClient, MetadataFormat, OwnedArchive, RegistryClientBuilder, RequestBuilder,
|
||||||
RetryParsingError, UvRetryableStrategy,
|
RetryParsingError, is_transient_network_error,
|
||||||
};
|
};
|
||||||
use uv_configuration::{KeyringProviderType, TrustedPublishing};
|
use uv_configuration::{KeyringProviderType, TrustedPublishing};
|
||||||
use uv_distribution_filename::{DistFilename, SourceDistExtension, SourceDistFilename};
|
use uv_distribution_filename::{DistFilename, SourceDistExtension, SourceDistFilename};
|
||||||
|
|
@ -484,31 +484,36 @@ pub async fn upload(
|
||||||
.map_err(|err| PublishError::PublishPrepare(group.file.clone(), Box::new(err)))?;
|
.map_err(|err| PublishError::PublishPrepare(group.file.clone(), Box::new(err)))?;
|
||||||
|
|
||||||
let result = request.send().await;
|
let result = request.send().await;
|
||||||
if UvRetryableStrategy.handle(&result) == Some(Retryable::Transient) {
|
let response = match result {
|
||||||
let retry_decision = retry_policy.should_retry(start_time, n_past_retries);
|
Ok(response) => {
|
||||||
if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision {
|
|
||||||
reporter.on_upload_complete(idx);
|
reporter.on_upload_complete(idx);
|
||||||
let duration = execute_after
|
response
|
||||||
.duration_since(SystemTime::now())
|
|
||||||
.unwrap_or_else(|_| Duration::default());
|
|
||||||
warn_user!(
|
|
||||||
"Transient failure while handling response for {}; retrying after {}s...",
|
|
||||||
registry,
|
|
||||||
duration.as_secs()
|
|
||||||
);
|
|
||||||
tokio::time::sleep(duration).await;
|
|
||||||
n_past_retries += 1;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
Err(err) => {
|
||||||
|
if is_transient_network_error(&err) {
|
||||||
|
let retry_decision = retry_policy.should_retry(start_time, n_past_retries);
|
||||||
|
if let reqwest_retry::RetryDecision::Retry { execute_after } = retry_decision {
|
||||||
|
let duration = execute_after
|
||||||
|
.duration_since(SystemTime::now())
|
||||||
|
.unwrap_or_else(|_| Duration::default());
|
||||||
|
warn_user!(
|
||||||
|
"Transient failure while handling response for {}; retrying after {}s...",
|
||||||
|
registry,
|
||||||
|
duration.as_secs()
|
||||||
|
);
|
||||||
|
tokio::time::sleep(duration).await;
|
||||||
|
n_past_retries += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let response = result.map_err(|err| {
|
return Err(PublishError::PublishSend(
|
||||||
PublishError::PublishSend(
|
group.file.clone(),
|
||||||
group.file.clone(),
|
registry.clone().into(),
|
||||||
registry.clone().into(),
|
PublishSendError::ReqwestMiddleware(err).into(),
|
||||||
PublishSendError::ReqwestMiddleware(err).into(),
|
));
|
||||||
)
|
}
|
||||||
})?;
|
};
|
||||||
|
|
||||||
return match handle_response(registry, response).await {
|
return match handle_response(registry, response).await {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,9 @@ impl ProgressReporter {
|
||||||
Direction::Download => "Downloaded",
|
Direction::Download => "Downloaded",
|
||||||
Direction::Upload => "Uploaded",
|
Direction::Upload => "Uploaded",
|
||||||
Direction::Extract => "Extracted",
|
Direction::Extract => "Extracted",
|
||||||
},
|
}
|
||||||
|
.bold()
|
||||||
|
.cyan(),
|
||||||
progress.message()
|
progress.message()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue