1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
//! Retry with exponential backoff.
//!
//! Provides [`retry_with_backoff`] which retries an operation up to a maximum
//! number of attempts, sleeping between attempts with an exponentially
//! increasing delay (doubling each time) starting from `base_delay`.
//!
//! Notes:
//! - The final error from the last attempt is returned on exhaustion.
//! - Sleep uses `std::thread::sleep`, making this a blocking API.
//! - Duration multiplication uses `saturating_mul(2)` to avoid overflow.
//!
//! Basic example:
//! ```rust
//! use toolchest::functions::retry_with_backoff;
//! use std::time::Duration;
//!
//! let mut tries = 0;
//! let result: Result<&'static str, &'static str> = retry_with_backoff(3, Duration::from_millis(5), || {
//! tries += 1;
//! if tries < 3 { Err("not yet") } else { Ok("ok") }
//! });
//! assert_eq!(result.unwrap(), "ok");
//! ```
use thread;
use Duration;
/// Retry with exponential backoff starting at `base_delay`.
///
/// - `attempts`: maximum number of times to try `op` (must be ≥ 1).
/// - `base_delay`: initial delay before the second attempt; doubles each retry.
/// - `op`: operation returning `Result<T, E>`.
///
/// Returns `Ok(T)` on the first successful attempt, or `Err(E)` from the last
/// attempt when attempts are exhausted.
///
/// Example that always fails and returns the last error:
/// ```rust
/// use toolchest::functions::retry_with_backoff;
/// use std::time::Duration;
/// let res: Result<(), &str> = retry_with_backoff(2, Duration::from_millis(1), || Err("oops"));
/// assert_eq!(res.unwrap_err(), "oops");
/// ```