pub struct Backoff { /* private fields */ }Expand description
A retry backoff policy.
Backoff is a small, Copy value. Construct one with Backoff::constant,
Backoff::linear, or Backoff::exponential, then optionally cap it with
Backoff::with_max_delay and Backoff::with_max_retries.
Backoff::delay takes a zero-based attempt number (attempt 0 is the wait
before the first retry) and returns the delay, or None when the retry limit
has been reached.
Implementations§
Source§impl Backoff
impl Backoff
Sourcepub const fn linear(base: Duration, step: Duration) -> Self
pub const fn linear(base: Duration, step: Duration) -> Self
A linear backoff: attempt n waits base + step * n.
Sourcepub const fn exponential(base: Duration, factor: u32) -> Self
pub const fn exponential(base: Duration, factor: u32) -> Self
An exponential backoff: attempt n waits base * factor^n.
factor is the integer multiplier (e.g. 2 doubles each attempt). A
factor below 2 makes the policy behave like Backoff::constant.
Examples found in repository?
14fn main() {
15 // 100ms base, double each attempt, capped at 2s, up to 5 retries.
16 let policy = Backoff::exponential(Duration::from_millis(100), 2)
17 .with_max_delay(Duration::from_secs(2))
18 .with_max_retries(5);
19
20 // A tiny deterministic PRNG stands in for a real RNG so the example output
21 // is reproducible. In real code use `rand`, `getrandom`, or a hardware RNG.
22 let mut seed: u32 = 0x9e37_79b9;
23 let mut next_rand = move || {
24 seed ^= seed << 13;
25 seed ^= seed >> 17;
26 seed ^= seed << 5;
27 seed
28 };
29
30 println!("attempt base-delay jittered-delay");
31 for (attempt, base) in policy.delays().enumerate() {
32 let jittered = full_jitter(base, next_rand());
33 println!("{attempt:>7} {base:>10?} {jittered:>14?}");
34 // In a real loop you would: sleep(jittered); if try_operation().is_ok() { break; }
35 }
36
37 println!("\nretry limit reached; giving up");
38}Sourcepub const fn with_max_delay(self, max_delay: Duration) -> Self
pub const fn with_max_delay(self, max_delay: Duration) -> Self
Caps every computed delay at max_delay.
Examples found in repository?
14fn main() {
15 // 100ms base, double each attempt, capped at 2s, up to 5 retries.
16 let policy = Backoff::exponential(Duration::from_millis(100), 2)
17 .with_max_delay(Duration::from_secs(2))
18 .with_max_retries(5);
19
20 // A tiny deterministic PRNG stands in for a real RNG so the example output
21 // is reproducible. In real code use `rand`, `getrandom`, or a hardware RNG.
22 let mut seed: u32 = 0x9e37_79b9;
23 let mut next_rand = move || {
24 seed ^= seed << 13;
25 seed ^= seed >> 17;
26 seed ^= seed << 5;
27 seed
28 };
29
30 println!("attempt base-delay jittered-delay");
31 for (attempt, base) in policy.delays().enumerate() {
32 let jittered = full_jitter(base, next_rand());
33 println!("{attempt:>7} {base:>10?} {jittered:>14?}");
34 // In a real loop you would: sleep(jittered); if try_operation().is_ok() { break; }
35 }
36
37 println!("\nretry limit reached; giving up");
38}Sourcepub const fn with_max_retries(self, max_retries: u32) -> Self
pub const fn with_max_retries(self, max_retries: u32) -> Self
Limits the policy to at most max_retries retries.
After this, delay returns None for attempt numbers
>= max_retries.
Examples found in repository?
14fn main() {
15 // 100ms base, double each attempt, capped at 2s, up to 5 retries.
16 let policy = Backoff::exponential(Duration::from_millis(100), 2)
17 .with_max_delay(Duration::from_secs(2))
18 .with_max_retries(5);
19
20 // A tiny deterministic PRNG stands in for a real RNG so the example output
21 // is reproducible. In real code use `rand`, `getrandom`, or a hardware RNG.
22 let mut seed: u32 = 0x9e37_79b9;
23 let mut next_rand = move || {
24 seed ^= seed << 13;
25 seed ^= seed >> 17;
26 seed ^= seed << 5;
27 seed
28 };
29
30 println!("attempt base-delay jittered-delay");
31 for (attempt, base) in policy.delays().enumerate() {
32 let jittered = full_jitter(base, next_rand());
33 println!("{attempt:>7} {base:>10?} {jittered:>14?}");
34 // In a real loop you would: sleep(jittered); if try_operation().is_ok() { break; }
35 }
36
37 println!("\nretry limit reached; giving up");
38}Sourcepub const fn max_retries(&self) -> Option<u32>
pub const fn max_retries(&self) -> Option<u32>
Returns the retry limit, if any.
Sourcepub fn delay(&self, attempt: u32) -> Option<Duration>
pub fn delay(&self, attempt: u32) -> Option<Duration>
Returns the delay to wait before retry attempt (zero-based), or None
if the retry limit has been reached.
The result is always clamped to max_delay. All
arithmetic saturates and the computation runs in bounded time, so large
attempt numbers never overflow, panic, or hang.
Sourcepub const fn delays(&self) -> Delays ⓘ
pub const fn delays(&self) -> Delays ⓘ
Returns an iterator over the delays for attempts 0, 1, 2, ....
The iterator ends when the retry limit is reached. With no retry limit it is infinite.
Examples found in repository?
14fn main() {
15 // 100ms base, double each attempt, capped at 2s, up to 5 retries.
16 let policy = Backoff::exponential(Duration::from_millis(100), 2)
17 .with_max_delay(Duration::from_secs(2))
18 .with_max_retries(5);
19
20 // A tiny deterministic PRNG stands in for a real RNG so the example output
21 // is reproducible. In real code use `rand`, `getrandom`, or a hardware RNG.
22 let mut seed: u32 = 0x9e37_79b9;
23 let mut next_rand = move || {
24 seed ^= seed << 13;
25 seed ^= seed >> 17;
26 seed ^= seed << 5;
27 seed
28 };
29
30 println!("attempt base-delay jittered-delay");
31 for (attempt, base) in policy.delays().enumerate() {
32 let jittered = full_jitter(base, next_rand());
33 println!("{attempt:>7} {base:>10?} {jittered:>14?}");
34 // In a real loop you would: sleep(jittered); if try_operation().is_ok() { break; }
35 }
36
37 println!("\nretry limit reached; giving up");
38}