async_retry/
async_retry.rs1use std::future::Future;
14use std::ops::ControlFlow;
15use std::pin::Pin;
16use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker};
17use std::time::Duration;
18
19use sisyphus::{retry_async, ExponentialBackoff, PolicyExt, RetryError};
20
21async fn fake_sleep(delay: Duration) {
23 println!(" (would await timer for {delay:?})");
24}
25
26async fn run() -> Result<u32, RetryError<&'static str>> {
27 let policy = ExponentialBackoff::new(Duration::from_millis(10), 2.0).max_attempts(5);
28 let mut attempt = 0u32;
29
30 retry_async(
31 policy,
32 || {
33 attempt += 1;
34 async move {
35 println!("async attempt {attempt}");
36 if attempt < 4 {
37 ControlFlow::Continue("service unavailable")
38 } else {
39 ControlFlow::Break(attempt)
40 }
41 }
42 },
43 fake_sleep,
45 )
46 .await
47}
48
49fn main() {
50 match block_on(run()) {
51 Ok(attempts) => println!("succeeded on attempt {attempts}"),
52 Err(RetryError::Exhausted(last)) => println!("exhausted; last state: {last}"),
53 }
54}
55
56fn block_on<F: Future>(mut fut: F) -> F::Output {
58 fn noop(_: *const ()) {}
59 fn clone(_: *const ()) -> RawWaker {
60 RawWaker::new(std::ptr::null(), &VTABLE)
61 }
62 static VTABLE: RawWakerVTable = RawWakerVTable::new(clone, noop, noop, noop);
63
64 let waker = unsafe { Waker::from_raw(RawWaker::new(std::ptr::null(), &VTABLE)) };
66 let mut cx = Context::from_waker(&waker);
67 let mut fut = unsafe { Pin::new_unchecked(&mut fut) };
70 loop {
71 if let Poll::Ready(v) = fut.as_mut().poll(&mut cx) {
72 return v;
73 }
74 }
75}