Skip to main content

quick_start/
quick_start.rs

1//! The canonical sync use case: retry a flaky operation with exponential
2//! backoff, bounded by a max delay and a max number of attempts, sleeping the
3//! real thread between tries.
4//!
5//! Run with:
6//!
7//! ```text
8//! cargo run --example quick_start
9//! ```
10
11use std::ops::ControlFlow;
12use std::time::{Duration, Instant};
13
14use sisyphus::{retry_sync, ExponentialBackoff, PolicyExt, RetryError};
15
16/// A fake service that fails a few times before succeeding.
17fn flaky_connect(attempt: u32) -> Result<&'static str, &'static str> {
18    if attempt < 4 {
19        Err("connection refused")
20    } else {
21        Ok("connected")
22    }
23}
24
25fn main() {
26    let policy = ExponentialBackoff::new(Duration::from_millis(50), 2.0)
27        .with_max_delay(Duration::from_secs(1))
28        .max_attempts(6);
29
30    let mut attempt = 0u32;
31    let started = Instant::now();
32
33    let result: Result<&str, RetryError<&str>> = retry_sync(
34        policy,
35        || {
36            attempt += 1;
37            match flaky_connect(attempt) {
38                Ok(ok) => ControlFlow::Break(ok),
39                Err(transient) => {
40                    println!("attempt {attempt} failed: {transient}");
41                    ControlFlow::Continue(transient)
42                }
43            }
44        },
45        // The execution side is entirely yours; here we block the OS thread.
46        |delay| {
47            println!("  backing off for {delay:?}");
48            std::thread::sleep(delay);
49        },
50    );
51
52    match result {
53        Ok(msg) => println!(
54            "success after {attempt} attempts in {:?}: {msg}",
55            started.elapsed()
56        ),
57        Err(RetryError::Exhausted(last)) => {
58            println!("gave up after {attempt} attempts; last error: {last}");
59        }
60    }
61}