use std::time::Duration;
#[derive(Debug, Clone)]
pub struct RetryConfig {
pub initial_delay: Duration,
pub multiplier: f64,
pub max_delay: Duration,
pub max_retries: usize,
}
impl Default for RetryConfig {
fn default() -> Self {
RetryConfig {
initial_delay: Duration::from_millis(500),
multiplier: 2.0,
max_delay: Duration::from_secs(5),
max_retries: 5,
}
}
}
impl RetryConfig {
pub fn none() -> Self {
RetryConfig {
initial_delay: Duration::from_millis(0),
multiplier: 0.0,
max_delay: Duration::from_secs(0),
max_retries: 0,
}
}
pub fn compute_delay(&self, attempt_count: usize) -> Duration {
if attempt_count == 0 {
panic!("attempt_count cannot be 0")
}
if attempt_count > self.max_retries {
panic!(
"attempt_count ({}) is greater than max_retries ({})",
attempt_count, self.max_retries
);
}
let factor = self.multiplier.powi((attempt_count - 1) as i32);
let mut delay = self.initial_delay.mul_f64(factor);
if delay > self.max_delay {
delay = self.max_delay;
}
delay
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
#[should_panic(expected = "attempt_count (1) is greater than max_retries (0)")]
fn test_no_retry() {
let config = RetryConfig::none();
assert_eq!(config.compute_delay(1), Duration::from_secs(0));
}
#[test]
#[should_panic(expected = "attempt_count cannot be 0")]
fn test_compute_delay_panics_with_0() {
RetryConfig::default().compute_delay(0);
}
#[test]
#[should_panic(expected = "attempt_count (6) is greater than max_retries (5)")]
fn test_compute_delay_panics_after_max_attempts() {
RetryConfig::default().compute_delay(6);
}
#[test]
fn test_default_retry() {
let config = RetryConfig::default();
assert_eq!(config.compute_delay(1), Duration::from_millis(500));
assert_eq!(config.compute_delay(2), Duration::from_millis(1000));
assert_eq!(config.compute_delay(3), Duration::from_secs(2));
assert_eq!(config.compute_delay(4), Duration::from_secs(4));
assert_eq!(config.compute_delay(5), Duration::from_secs(5));
}
#[test]
fn test_long_retry_count() {
let config = RetryConfig {
initial_delay: Duration::from_millis(500),
multiplier: 2.0,
max_delay: Duration::from_secs(10),
max_retries: 8,
};
assert_eq!(config.compute_delay(1), Duration::from_millis(500));
assert_eq!(config.compute_delay(2), Duration::from_millis(1000));
assert_eq!(config.compute_delay(3), Duration::from_secs(2));
assert_eq!(config.compute_delay(4), Duration::from_secs(4));
assert_eq!(config.compute_delay(5), Duration::from_secs(8));
assert_eq!(config.compute_delay(6), Duration::from_secs(10));
assert_eq!(config.compute_delay(7), Duration::from_secs(10));
assert_eq!(config.compute_delay(8), Duration::from_secs(10));
}
}