use std::time::Duration;
#[derive(Debug, Clone)]
pub struct RetryPolicy {
pub(crate) max_retries: u32,
pub(crate) backoff: Backoff,
}
#[derive(Debug, Clone)]
pub(crate) enum Backoff {
Fixed(Duration),
Exponential { base: Duration, max: Duration },
}
impl RetryPolicy {
#[must_use]
pub fn fixed(max_retries: u32, delay: Duration) -> Self {
Self {
max_retries,
backoff: Backoff::Fixed(delay),
}
}
#[must_use]
pub fn exponential(max_retries: u32, base: Duration) -> Self {
Self {
max_retries,
backoff: Backoff::Exponential {
base,
max: Duration::from_secs(30),
},
}
}
#[must_use]
pub fn with_max_delay(mut self, max: Duration) -> Self {
if let Backoff::Exponential { max: ref mut m, .. } = self.backoff {
*m = max;
}
self
}
pub(crate) fn delay_for(&self, attempt: u32) -> Duration {
match self.backoff {
Backoff::Fixed(d) => d,
Backoff::Exponential { base, max } => {
let multiplier = 1u64.checked_shl(attempt).unwrap_or(u64::MAX);
let delay = base.saturating_mul(multiplier.try_into().unwrap_or(u32::MAX));
delay.min(max)
}
}
}
}