aws_iot_device_sdk/
backoff_algo.rs

1/// This library uses the "Full Jitter" strategy for the exponential backoff with jitter algorithm.
2/// More information about the algorithm can be seen in the 
3/// [Exponential Backoff and Jitter](https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/) 
4/// AWS blog.
5#[derive(Debug, PartialEq)]
6pub struct BackoffAlgorithm {
7    /// The maximum backoff base (in milliseconds) between consecutive retry attempts.
8    pub max: usize,
9    /// The total number of retry attempts completed.
10    /// This value is incremented on every call to #BackoffAlgorithm_GetNextBackoff API.
11    /// pub attemptsDone: usize,
12    /// The maximum backoff value (in milliseconds) for the next retry attempt.
13    pub base: usize,
14    /// The maximum number of retry attempts.
15    /// pub maxRetryAttempts: usize,
16    power: usize,
17    pub value: usize,
18    pub rand: Option<usize>,
19}
20
21impl BackoffAlgorithm {
22    /// Initializes the context for using backoff algorithm.
23    pub fn new(base: usize, max: usize, rand: Option<usize>) -> BackoffAlgorithm {
24        BackoffAlgorithm {
25            base,
26            max,
27            power: base,
28            value: base,
29            rand,
30        }
31    }
32    /// Simple exponential backoff and jitter function that provides the
33    /// delay value for the next retry attempt.
34    pub fn get(&self) -> usize {
35        self.value
36    }
37}
38
39impl Iterator for BackoffAlgorithm {
40    type Item = usize;
41
42    fn next(&mut self) -> Option<Self::Item> {
43        self.value = self.power + self.rand.unwrap_or_default() % self.power;
44        self.power += self.power;
45
46        if self.value <= self.max {
47            Some(self.value)
48        } else {
49            None
50        }
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use rand::random;
57
58    use crate::backoff_algo;
59    #[test]
60    fn next_test() {
61        let mut bfa = backoff_algo::BackoffAlgorithm::new(1, 16, None);
62        assert_eq!(bfa.next(), Some(1));
63        assert_eq!(bfa.get(), 1);
64        assert_eq!(bfa.next(), Some(2));
65        assert_eq!(bfa.get(), 2);
66        assert_eq!(bfa.next(), Some(4));
67        assert_eq!(bfa.get(), 4);
68        assert_eq!(bfa.next(), Some(8));
69        assert_eq!(bfa.next(), Some(16));
70        assert_eq!(bfa.get(), 16);
71        assert_eq!(bfa.next(), None);
72        assert_eq!(bfa.get(), 32);
73    }
74    #[test]
75    fn next_with_random_test() {
76        let mut bfa = backoff_algo::BackoffAlgorithm::new(8, 64, random());
77        println!("{}", bfa.get());
78        assert!(bfa.next() <= Some(16));
79        println!("{}", bfa.get());
80        assert!(bfa.next() <= Some(32));
81        println!("{}", bfa.get());
82        assert!(bfa.next() <= Some(64));
83        println!("{}", bfa.get());
84    }
85}