use std::cell::Cell;
use std::ops::ControlFlow;
use std::time::Duration;
use sisyphus::{retry_sync, Clock, ExponentialBackoff, PolicyExt, RetryError};
struct VirtualClock {
now_ms: Cell<u64>,
}
impl VirtualClock {
fn new() -> Self {
Self {
now_ms: Cell::new(0),
}
}
fn advance(&self, by: Duration) {
self.now_ms.set(self.now_ms.get() + by.as_millis() as u64);
}
}
impl Clock for VirtualClock {
type Instant = u64;
fn now(&self) -> u64 {
self.now_ms.get()
}
fn duration_since(&self, earlier: u64, now: u64) -> Duration {
Duration::from_millis(now.saturating_sub(earlier))
}
}
fn main() {
let clock = VirtualClock::new();
let policy = ExponentialBackoff::new(Duration::from_millis(100), 2.0)
.max_elapsed_time(&clock, Duration::from_secs(2));
let mut attempt = 0u32;
let outcome: Result<(), RetryError<u32>> = retry_sync(
policy,
|| {
attempt += 1;
ControlFlow::Continue(attempt)
},
|delay| {
clock.advance(delay);
println!("slept {delay:?}, virtual t = {}ms", clock.now());
},
);
match outcome {
Ok(()) => unreachable!("operation never breaks"),
Err(RetryError::Exhausted(last)) => {
println!(
"budget exhausted after {last} attempts at virtual t = {}ms",
clock.now()
);
}
}
}