bililive_core/retry/
policy.rs

1use std::time::Duration;
2
3use rand::distributions::Uniform;
4use rand::{thread_rng, Rng};
5
6/// An exponential backoff retry policy.
7#[derive(Debug, Clone)]
8pub struct BEBIterator {
9    unit: Duration,
10    truncate: u32,
11    fail: u32,
12    count: u32,
13}
14
15impl Default for BEBIterator {
16    fn default() -> Self {
17        Self::new(Duration::from_secs(1), 5, 10)
18    }
19}
20
21impl BEBIterator {
22    /// Create an exponential backoff retry policy
23    ///
24    /// # Arguments
25    ///
26    /// * `unit`: unit duration of delay.
27    /// * `truncate`: after a continuous failure of such counts, the delay stops increasing.
28    /// * `fail`: after a continuous failure of such counts, the connection closes.
29    ///
30    /// returns: `BEBIterator`
31    ///
32    /// # Panics
33    ///
34    /// Truncate is expected to less than fail. Otherwise, a panic will occur.
35    #[must_use]
36    pub fn new(unit: Duration, truncate: u32, fail: u32) -> Self {
37        assert!(truncate < fail, "truncate >= fail");
38        Self {
39            unit,
40            truncate,
41            fail,
42            count: 0,
43        }
44    }
45}
46
47impl Iterator for BEBIterator {
48    type Item = Duration;
49
50    fn next(&mut self) -> Option<Self::Item> {
51        if self.count >= self.fail {
52            None
53        } else {
54            let max_delay = 2_u32.pow(if self.count >= self.truncate {
55                self.truncate
56            } else {
57                self.count
58            });
59            let between = Uniform::new_inclusive(0, max_delay * 100);
60            let units = thread_rng().sample(between);
61            Some(self.unit * units / 100)
62        }
63    }
64}