Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.6.2 #15

Merged
merged 4 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "reqwest-cross"
version = "0.6.1"
version = "0.6.2"
authors = ["One <[email protected]>"]
categories = ["web-programming::http-client", "wasm"]
documentation = "https://docs.rs/reqwest-cross"
Expand All @@ -25,6 +25,7 @@ rand = "0.8.5"
reqwest = { version = "0.12.12", default-features = false }
thiserror = "2.0.9"
tracing = "0.1.41"
web-time = "1.1.0"

# For native compilation
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
Expand Down
42 changes: 22 additions & 20 deletions src/data_state_retry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use tracing::warn;
use crate::{data_state::CanMakeProgress, Awaiting, DataState, ErrorBounds};
use std::fmt::Debug;
use std::ops::Range;
use std::time::{Duration, Instant};

/// Automatically retries with a delay on failure until attempts are exhausted
#[derive(Debug)]
Expand All @@ -17,7 +16,7 @@ pub struct DataStateRetry<T, E: ErrorBounds = anyhow::Error> {

attempts_left: u8,
inner: DataState<T, E>, // Not public to ensure resets happen as they should
next_allowed_attempt: Instant,
next_allowed_attempt: u128,
}

impl<T, E: ErrorBounds> DataStateRetry<T, E> {
Expand All @@ -35,9 +34,8 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
self.attempts_left
}

/// The instant that needs to be waited for before another attempt is
/// allowed
pub fn next_allowed_attempt(&self) -> Instant {
/// The number of millis after the epoch that an attempt is allowed
pub fn next_allowed_attempt(&self) -> u128 {
self.next_allowed_attempt
}

Expand Down Expand Up @@ -112,17 +110,17 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
format!(
"{} attempt(s) left. {} seconds before retry. {e}",
self.attempts_left,
wait_left.as_secs()
wait_left / 1000
),
);
if ui.button("Stop Trying").clicked() {
self.attempts_left = 0;
}
let can_make_progress = self.start_or_poll(fetch_fn);
debug_assert!(
can_make_progress.is_able_to_make_progress(),
"This should be able to make progress"
);
if ui.button("Stop Trying").clicked() {
self.attempts_left = 0;
}
}
CanMakeProgress::AbleToMakeProgress
}
Expand All @@ -140,12 +138,9 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
DataState::None => {
// Going to make an attempt, set when the next attempt is allowed
use rand::Rng as _;
let wait_time_in_millis = rand::thread_rng()
.gen_range(self.retry_delay_millis.clone())
.into();
self.next_allowed_attempt = Instant::now()
.checked_add(Duration::from_millis(wait_time_in_millis))
.expect("failed to get random delay, value was out of range");
let wait_time_in_millis =
rand::thread_rng().gen_range(self.retry_delay_millis.clone());
self.next_allowed_attempt = millis_since_epoch() + wait_time_in_millis as u128;

self.inner.start_request(fetch_fn)
}
Expand All @@ -162,7 +157,7 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
CanMakeProgress::UnableToMakeProgress
} else {
let wait_left = wait_before_next_attempt(self.next_allowed_attempt);
if wait_left.is_zero() {
if wait_left == 0 {
warn!(?err_msg, ?self.attempts_left, "retrying request");
self.attempts_left -= 1;
self.inner = DataState::None;
Expand All @@ -176,7 +171,7 @@ impl<T, E: ErrorBounds> DataStateRetry<T, E> {
/// Resets the attempts taken
pub fn reset_attempts(&mut self) {
self.attempts_left = self.max_attempts;
self.next_allowed_attempt = Instant::now();
self.next_allowed_attempt = millis_since_epoch();
}

/// Clear stored data
Expand Down Expand Up @@ -214,7 +209,7 @@ impl<T, E: ErrorBounds> Default for DataStateRetry<T, E> {
max_attempts: 3,
retry_delay_millis: 1000..5000,
attempts_left: 3,
next_allowed_attempt: Instant::now(),
next_allowed_attempt: millis_since_epoch(),
}
}
}
Expand All @@ -232,8 +227,15 @@ impl<T, E: ErrorBounds> AsMut<DataStateRetry<T, E>> for DataStateRetry<T, E> {
}

/// The duration before the next attempt will be made
fn wait_before_next_attempt(next_allowed_attempt: Instant) -> Duration {
next_allowed_attempt.saturating_duration_since(Instant::now())
fn wait_before_next_attempt(next_allowed_attempt: u128) -> u128 {
next_allowed_attempt.saturating_sub(millis_since_epoch())
}

fn millis_since_epoch() -> u128 {
web_time::SystemTime::UNIX_EPOCH
.elapsed()
.expect("expected date on system to be after the epoch")
.as_millis()
}

// TODO 4: Use mocking to add tests ensuring retires are executed
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,6 @@ pub use yield_::yield_now;
// Exported to ensure version used matches
pub use futures::channel::oneshot;
pub use reqwest;

// TODO 4: Add browser test to ensure we don't break WASM by accident. Even if
// it can compile it might not be browser safe
Loading