1use std::time::Duration;
2
3fn randomize(backoff_ms: usize) -> usize {
4 let new_value = (fastrand::usize(750..=1250) * backoff_ms) / 1000;
5 if new_value == 0 {
6 backoff_ms
7 } else {
8 new_value
9 }
10}
11
12pub struct Exponential<Fn> {
14 multiplier: usize,
15 max_multiplier: usize,
16 exponent: usize,
17 transform: Fn,
18}
19
20impl Default for Exponential<fn(usize) -> usize> {
21 fn default() -> Self {
22 Exponential {
23 multiplier: 1,
24 max_multiplier: 1000,
25 exponent: 1,
26 transform: std::convert::identity,
27 }
28 }
29}
30
31impl Exponential<fn(usize) -> usize> {
32 pub fn default_with_random() -> Self {
34 Exponential {
35 multiplier: 1,
36 max_multiplier: 1000,
37 exponent: 1,
38 transform: randomize,
39 }
40 }
41}
42
43impl<Transform> Exponential<Transform>
44where
45 Transform: Fn(usize) -> usize,
46{
47 pub fn until_no_remaining(&mut self, time: Duration) -> impl Iterator<Item = Duration> + '_ {
49 let mut elapsed = Duration::default();
50 let mut stop_next_iteration = false;
51 self.take_while(move |d| {
52 if stop_next_iteration {
53 false
54 } else {
55 elapsed += *d;
56 if elapsed > time {
57 stop_next_iteration = true;
58 }
59 true
60 }
61 })
62 }
63}
64
65impl<Transform> Iterator for Exponential<Transform>
66where
67 Transform: Fn(usize) -> usize,
68{
69 type Item = Duration;
70
71 fn next(&mut self) -> Option<Self::Item> {
72 let wait = Duration::from_millis((self.transform)(self.multiplier) as u64);
73
74 self.multiplier += 2 * self.exponent + 1;
75 if self.multiplier > self.max_multiplier {
76 self.multiplier = self.max_multiplier;
77 } else {
78 self.exponent += 1;
79 }
80 Some(wait)
81 }
82}