1use std::{
2 thread::{self, yield_now},
3 time::Duration,
4};
5
6use rand::{rng, Rng};
7
8pub struct Backoff {
9 current_step: u32,
10 max_sleep: Duration,
11}
12
13impl Backoff {
14 pub fn new_us(max_sleep: u64) -> Self {
15 let max_sleep = Duration::from_micros(max_sleep);
16 Self {
17 current_step: 0,
18 max_sleep,
19 }
20 }
21
22 pub fn new_ms(max_sleep: u64) -> Self {
23 let max_sleep = Duration::from_millis(max_sleep);
24 Self {
25 current_step: 0,
26 max_sleep,
27 }
28 }
29
30 pub fn reset(&mut self) {
32 self.current_step = 0;
33 }
34
35 pub fn snooze(&mut self) {
37 if self.current_step < 10 {
38 yield_now();
39 } else {
40 let base = 1u64 << (self.current_step - 10).min(10);
42 let sleep_micros = base * 10;
43 let jitter: u64 = rng().random_range(0..sleep_micros / 2);
44 let total_sleep = Duration::from_micros(
45 (sleep_micros + jitter).min(self.max_sleep.as_micros() as u64),
46 );
47
48 thread::sleep(total_sleep);
49 }
50
51 self.current_step = self.current_step.saturating_add(1);
52 }
53}