mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(install): retry downloads of registry info / tarballs (#26278)
Fixes #26085. Adds a basic retry utility with some defaults, starts off with a 100ms wait, then 250ms, then 500ms I've applied the retry in the http client, reusing an existing function, so this also applies to retrying downloads of deno binaries in `upgrade` and `compile`. I can make a separate function that doesn't retry so this doesn't affect `upgrade` and `compile`, but it seemed desirable to have retries there too, so I left it in.
This commit is contained in:
parent
40b1c42138
commit
7c3c13cecf
7 changed files with 68 additions and 11 deletions
|
@ -470,15 +470,23 @@ impl HttpClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn download_with_progress(
|
pub async fn download_with_progress_and_retries(
|
||||||
&self,
|
&self,
|
||||||
url: Url,
|
url: Url,
|
||||||
maybe_header: Option<(HeaderName, HeaderValue)>,
|
maybe_header: Option<(HeaderName, HeaderValue)>,
|
||||||
progress_guard: &UpdateGuard,
|
progress_guard: &UpdateGuard,
|
||||||
) -> Result<Option<Vec<u8>>, DownloadError> {
|
) -> Result<Option<Vec<u8>>, DownloadError> {
|
||||||
self
|
crate::util::retry::retry(
|
||||||
.download_inner(url, maybe_header, Some(progress_guard))
|
|| {
|
||||||
.await
|
self.download_inner(
|
||||||
|
url.clone(),
|
||||||
|
maybe_header.clone(),
|
||||||
|
Some(progress_guard),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|e| matches!(e, DownloadError::BadResponse(_) | DownloadError::Fetch(_)),
|
||||||
|
)
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_redirected_url(
|
pub async fn get_redirected_url(
|
||||||
|
|
11
cli/npm/managed/cache/registry_info.rs
vendored
11
cli/npm/managed/cache/registry_info.rs
vendored
|
@ -202,10 +202,13 @@ impl RegistryInfoDownloader {
|
||||||
let guard = self.progress_bar.update(package_url.as_str());
|
let guard = self.progress_bar.update(package_url.as_str());
|
||||||
let name = name.to_string();
|
let name = name.to_string();
|
||||||
async move {
|
async move {
|
||||||
let maybe_bytes = downloader
|
let client = downloader.http_client_provider.get_or_create()?;
|
||||||
.http_client_provider
|
let maybe_bytes = client
|
||||||
.get_or_create()?
|
.download_with_progress_and_retries(
|
||||||
.download_with_progress(package_url, maybe_auth_header, &guard)
|
package_url,
|
||||||
|
maybe_auth_header,
|
||||||
|
&guard,
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
match maybe_bytes {
|
match maybe_bytes {
|
||||||
Some(bytes) => {
|
Some(bytes) => {
|
||||||
|
|
2
cli/npm/managed/cache/tarball.rs
vendored
2
cli/npm/managed/cache/tarball.rs
vendored
|
@ -172,7 +172,7 @@ impl TarballCache {
|
||||||
let guard = tarball_cache.progress_bar.update(&dist.tarball);
|
let guard = tarball_cache.progress_bar.update(&dist.tarball);
|
||||||
let result = tarball_cache.http_client_provider
|
let result = tarball_cache.http_client_provider
|
||||||
.get_or_create()?
|
.get_or_create()?
|
||||||
.download_with_progress(tarball_uri, maybe_auth_header, &guard)
|
.download_with_progress_and_retries(tarball_uri, maybe_auth_header, &guard)
|
||||||
.await;
|
.await;
|
||||||
let maybe_bytes = match result {
|
let maybe_bytes = match result {
|
||||||
Ok(maybe_bytes) => maybe_bytes,
|
Ok(maybe_bytes) => maybe_bytes,
|
||||||
|
|
|
@ -468,7 +468,11 @@ impl<'a> DenoCompileBinaryWriter<'a> {
|
||||||
self
|
self
|
||||||
.http_client_provider
|
.http_client_provider
|
||||||
.get_or_create()?
|
.get_or_create()?
|
||||||
.download_with_progress(download_url.parse()?, None, &progress)
|
.download_with_progress_and_retries(
|
||||||
|
download_url.parse()?,
|
||||||
|
None,
|
||||||
|
&progress,
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
let bytes = match maybe_bytes {
|
let bytes = match maybe_bytes {
|
||||||
|
|
|
@ -913,7 +913,7 @@ async fn download_package(
|
||||||
// text above which will stay alive after the progress bars are complete
|
// text above which will stay alive after the progress bars are complete
|
||||||
let progress = progress_bar.update("");
|
let progress = progress_bar.update("");
|
||||||
let maybe_bytes = client
|
let maybe_bytes = client
|
||||||
.download_with_progress(download_url.clone(), None, &progress)
|
.download_with_progress_and_retries(download_url.clone(), None, &progress)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("Failed downloading {download_url}. The version you requested may not have been built for the current architecture."))?;
|
.with_context(|| format!("Failed downloading {download_url}. The version you requested may not have been built for the current architecture."))?;
|
||||||
Ok(maybe_bytes)
|
Ok(maybe_bytes)
|
||||||
|
|
|
@ -14,6 +14,7 @@ pub mod logger;
|
||||||
pub mod path;
|
pub mod path;
|
||||||
pub mod progress_bar;
|
pub mod progress_bar;
|
||||||
pub mod result;
|
pub mod result;
|
||||||
|
pub mod retry;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod text_encoding;
|
pub mod text_encoding;
|
||||||
pub mod unix;
|
pub mod unix;
|
||||||
|
|
41
cli/util/retry.rs
Normal file
41
cli/util/retry.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||||
|
|
||||||
|
use std::future::Future;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
pub fn retry<
|
||||||
|
F: FnMut() -> Fut,
|
||||||
|
T,
|
||||||
|
E,
|
||||||
|
Fut: Future<Output = Result<T, E>>,
|
||||||
|
ShouldRetry: FnMut(&E) -> bool,
|
||||||
|
>(
|
||||||
|
mut f: F,
|
||||||
|
mut should_retry: ShouldRetry,
|
||||||
|
) -> impl Future<Output = Result<T, E>> {
|
||||||
|
const WAITS: [Duration; 3] = [
|
||||||
|
Duration::from_millis(100),
|
||||||
|
Duration::from_millis(250),
|
||||||
|
Duration::from_millis(500),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut waits = WAITS.into_iter();
|
||||||
|
async move {
|
||||||
|
let mut first_result = None;
|
||||||
|
loop {
|
||||||
|
let result = f().await;
|
||||||
|
match result {
|
||||||
|
Ok(r) => return Ok(r),
|
||||||
|
Err(e) if !should_retry(&e) => return Err(e),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
if first_result.is_none() {
|
||||||
|
first_result = Some(result);
|
||||||
|
}
|
||||||
|
let Some(wait) = waits.next() else {
|
||||||
|
return first_result.unwrap();
|
||||||
|
};
|
||||||
|
tokio::time::sleep(wait).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue