Skip to content

Commit

Permalink
Actually retry on HTTP errors (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
yeetfield authored Jul 18, 2023
1 parent 18f6618 commit 166d349
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
include:
- target: x86_64-unknown-linux-musl
asset: ozy-Linux-x86_64
runs-on: ubuntu-18.04
runs-on: ubuntu-22.04
- target: x86_64-apple-darwin
asset: ozy-Darwin-x86_64
runs-on: macos-12
Expand Down
65 changes: 51 additions & 14 deletions rozy/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use anyhow::Result;
use anyhow::{anyhow, Result};

fn is_request_retryable_based_on_error(err: &reqwest::Error) -> bool {
if err.is_timeout() || err.is_connect() {
Expand All @@ -10,30 +10,67 @@ fn is_request_retryable_based_on_error(err: &reqwest::Error) -> bool {
return false;
}

if let Some(code) = err.status() {
return match code.as_u16() {
408 | 425 | 429 | 500 | 502 | 503 | 504 => true, // https://stackoverflow.com/a/74627395/21956251
_ => false,
};
}

true
}

pub fn download_to(dest_path: &std::path::PathBuf, url: &str) -> Result<()> {
let tmp_dest_path = dest_path.clone().with_extension("tmp");
let mut dest_file = std::fs::File::create(&tmp_dest_path)?;

let mut num_tries = 5;
let mut wait_duration = std::time::Duration::from_millis(200);
let mut response = reqwest::blocking::get(url);
while let Err(err) = &response {
if num_tries < 0 || !is_request_retryable_based_on_error(err) {
// The final attempt will wait 12 seconds before proceeding
let num_tries = 8;
let wait_duration = std::time::Duration::from_millis(200);

for attempt_num in 0..num_tries {
if attempt_num > 0 {
let this_wait_duration = wait_duration * 2_u32.pow(attempt_num - 1);
eprintln!(
"Retrying, attempt #{} after sleeping for {}ms",
attempt_num,
this_wait_duration.as_millis()
);
std::thread::sleep(this_wait_duration);
}

let response = reqwest::blocking::get(url);
if let Err(err) = &response {
eprintln!("Error while making GET request: {}", err);
if is_request_retryable_based_on_error(err) {
continue;
}
break;
}

std::thread::sleep(wait_duration);
wait_duration *= 2;
num_tries -= 1;
let response = response?;
if let Err(err) = &response.error_for_status_ref() {
eprintln!("GET request failed: {}", err);
if is_request_retryable_based_on_error(err) {
continue;
}
break;
}

let content = response.bytes();
if let Err(err) = &content {
eprintln!("Error while making streaming response: {}", err);
if is_request_retryable_based_on_error(err) {
continue;
}
break;
}

response = reqwest::blocking::get(url);
let mut cursor = std::io::Cursor::new(content?);
std::io::copy(&mut cursor, &mut dest_file)?;
std::fs::rename(tmp_dest_path, dest_path)?;
return Ok(());
}

let mut content = std::io::Cursor::new(response?.bytes()?);
std::io::copy(&mut content, &mut dest_file)?;
std::fs::rename(tmp_dest_path, dest_path)?;
Ok(())
Err(anyhow!("Failed to download {}", url))
}

0 comments on commit 166d349

Please sign in to comment.