custom_clock/
custom_clock.rs1use std::cell::Cell;
14use std::ops::ControlFlow;
15use std::time::Duration;
16
17use sisyphus::{retry_sync, Clock, ExponentialBackoff, PolicyExt, RetryError};
18
19struct VirtualClock {
21 now_ms: Cell<u64>,
22}
23
24impl VirtualClock {
25 fn new() -> Self {
26 Self {
27 now_ms: Cell::new(0),
28 }
29 }
30 fn advance(&self, by: Duration) {
31 self.now_ms.set(self.now_ms.get() + by.as_millis() as u64);
32 }
33}
34
35impl Clock for VirtualClock {
36 type Instant = u64;
37
38 fn now(&self) -> u64 {
39 self.now_ms.get()
40 }
41
42 fn duration_since(&self, earlier: u64, now: u64) -> Duration {
43 Duration::from_millis(now.saturating_sub(earlier))
44 }
45}
46
47fn main() {
48 let clock = VirtualClock::new();
49
50 let policy = ExponentialBackoff::new(Duration::from_millis(100), 2.0)
52 .max_elapsed_time(&clock, Duration::from_secs(2));
53
54 let mut attempt = 0u32;
55 let outcome: Result<(), RetryError<u32>> = retry_sync(
56 policy,
57 || {
58 attempt += 1;
59 ControlFlow::Continue(attempt)
61 },
62 |delay| {
64 clock.advance(delay);
65 println!("slept {delay:?}, virtual t = {}ms", clock.now());
66 },
67 );
68
69 match outcome {
70 Ok(()) => unreachable!("operation never breaks"),
71 Err(RetryError::Exhausted(last)) => {
72 println!(
73 "budget exhausted after {last} attempts at virtual t = {}ms",
74 clock.now()
75 );
76 }
77 }
78}