use backoff::backoff::Backoff as BackoffTrait;
use backoff::ExponentialBackoff;
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct Retry {
pub retries: u32,
pub max_delay: Duration,
pub delay_factor: Duration,
pub randomization_factor: f64,
}
impl Default for Retry {
fn default() -> Self {
Self {
retries: 5,
max_delay: Duration::from_secs(30),
delay_factor: Duration::from_millis(100),
randomization_factor: 0.25,
}
}
}
#[derive(Debug)]
pub struct Backoff<'a> {
retry: &'a Retry,
tries: u32,
backoff: ExponentialBackoff,
}
impl<'a> Backoff<'a> {
pub fn new(retry: &Retry) -> Backoff {
let mut backoff = ExponentialBackoff {
max_elapsed_time: None, max_interval: retry.max_delay,
initial_interval: retry.delay_factor,
multiplier: 2.0, #[cfg(not(test))]
randomization_factor: retry.randomization_factor,
#[cfg(test)]
randomization_factor: 0.0,
..Default::default()
};
backoff.reset();
Backoff {
retry,
tries: 0,
backoff,
}
}
pub fn next_backoff(&mut self) -> Option<Duration> {
self.tries += 1;
if self.tries > self.retry.retries {
None
} else {
self.backoff.next_backoff()
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[tokio::test]
async fn backoff_three_retries() {
let retry = Retry {
retries: 3,
..Default::default()
};
let mut backoff = Backoff::new(&retry);
assert_eq!(backoff.next_backoff(), Some(Duration::from_millis(100)));
assert_eq!(backoff.next_backoff(), Some(Duration::from_millis(200)));
assert_eq!(backoff.next_backoff(), Some(Duration::from_millis(400)));
assert_eq!(backoff.next_backoff(), None); }
}