retry_strategy/strategy/
mod.rs1use std::time::Duration;
4use std::u64::MAX as U64_MAX;
5
6#[cfg(feature = "random")]
7mod random;
8
9#[cfg(feature = "random")]
10pub use random::{jitter, Range};
11
12#[derive(Debug)]
14pub struct Exponential {
15 current: u64,
16 factor: f64,
17}
18
19impl Exponential {
20 pub fn from_millis(base: u64) -> Self {
23 Exponential {
24 current: base,
25 factor: 2.0,
26 }
27 }
28
29 pub fn from_millis_with_base_factor(base: u64) -> Self {
33 Exponential {
34 current: base,
35 factor: base as f64,
36 }
37 }
38
39 pub fn from_millis_with_factor(base: u64, factor: f64) -> Self {
42 Exponential {
43 current: base,
44 factor,
45 }
46 }
47}
48
49impl Iterator for Exponential {
50 type Item = Duration;
51
52 fn next(&mut self) -> Option<Duration> {
53 let duration = Duration::from_millis(self.current);
54
55 let next = (self.current as f64) * self.factor;
56 self.current = if next > (U64_MAX as f64) {
57 U64_MAX
58 } else {
59 next as u64
60 };
61
62 Some(duration)
63 }
64}
65
66impl From<Duration> for Exponential {
67 fn from(duration: Duration) -> Self {
68 Self::from_millis(duration.as_millis() as u64)
69 }
70}
71
72#[derive(Debug)]
81pub struct Fibonacci {
82 curr: u64,
83 next: u64,
84}
85
86impl Fibonacci {
87 pub fn from_millis(millis: u64) -> Fibonacci {
89 Fibonacci {
90 curr: millis,
91 next: millis,
92 }
93 }
94}
95
96impl Iterator for Fibonacci {
97 type Item = Duration;
98
99 fn next(&mut self) -> Option<Duration> {
100 let duration = Duration::from_millis(self.curr);
101
102 if let Some(next_next) = self.curr.checked_add(self.next) {
103 self.curr = self.next;
104 self.next = next_next;
105 } else {
106 self.curr = self.next;
107 self.next = U64_MAX;
108 }
109
110 Some(duration)
111 }
112}
113
114impl From<Duration> for Fibonacci {
115 fn from(duration: Duration) -> Self {
116 Self::from_millis(duration.as_millis() as u64)
117 }
118}
119
120#[derive(Debug)]
122pub struct Fixed {
123 duration: Duration,
124}
125
126impl Fixed {
127 pub fn from_millis(millis: u64) -> Self {
129 Fixed {
130 duration: Duration::from_millis(millis),
131 }
132 }
133}
134
135impl Iterator for Fixed {
136 type Item = Duration;
137
138 fn next(&mut self) -> Option<Duration> {
139 Some(self.duration)
140 }
141}
142
143impl From<Duration> for Fixed {
144 fn from(delay: Duration) -> Self {
145 Self { duration: delay }
146 }
147}
148
149#[derive(Debug)]
151pub struct NoDelay;
152
153impl Iterator for NoDelay {
154 type Item = Duration;
155
156 fn next(&mut self) -> Option<Duration> {
157 Some(Duration::default())
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::{Exponential, Fibonacci};
164 use crate::ToDuration;
165 use std::time::Duration;
166 use std::u64::MAX as U64_MAX;
167
168 #[test]
169 fn test_opportunity() {
170 let mut iter = vec![100.ms(), 200.ms(), 300.ms()].into_iter();
171 assert_eq!(iter.next(), Some(Duration::from_millis(100)));
172 assert_eq!(iter.next(), Some(Duration::from_millis(200)));
173 assert_eq!(iter.next(), Some(Duration::from_millis(300)));
174 assert_eq!(iter.next(), None);
175 }
176
177 #[test]
178 fn exponential_with_factor() {
179 let mut iter = Exponential::from_millis_with_factor(1000, 2.0);
180 assert_eq!(iter.next(), Some(Duration::from_millis(1000)));
181 assert_eq!(iter.next(), Some(Duration::from_millis(2000)));
182 assert_eq!(iter.next(), Some(Duration::from_millis(4000)));
183 assert_eq!(iter.next(), Some(Duration::from_millis(8000)));
184 assert_eq!(iter.next(), Some(Duration::from_millis(16000)));
185 assert_eq!(iter.next(), Some(Duration::from_millis(32000)));
186 }
187
188 #[test]
189 fn exponential_overflow() {
190 let mut iter = Exponential::from_millis(U64_MAX);
191 assert_eq!(iter.next(), Some(Duration::from_millis(U64_MAX)));
192 assert_eq!(iter.next(), Some(Duration::from_millis(U64_MAX)));
193 }
194
195 #[test]
196 fn fibonacci() {
197 let mut iter = Fibonacci::from_millis(10);
198 assert_eq!(iter.next(), Some(Duration::from_millis(10)));
199 assert_eq!(iter.next(), Some(Duration::from_millis(10)));
200 assert_eq!(iter.next(), Some(Duration::from_millis(20)));
201 assert_eq!(iter.next(), Some(Duration::from_millis(30)));
202 assert_eq!(iter.next(), Some(Duration::from_millis(50)));
203 assert_eq!(iter.next(), Some(Duration::from_millis(80)));
204 }
205
206 #[test]
207 fn fibonacci_saturated() {
208 let mut iter = Fibonacci::from_millis(U64_MAX);
209 assert_eq!(iter.next(), Some(Duration::from_millis(U64_MAX)));
210 assert_eq!(iter.next(), Some(Duration::from_millis(U64_MAX)));
211 }
212}