use std::time::Duration;
#[derive(Clone)]
pub struct RetryPolicy {
pub max_attempts: u32,
pub on_retry: InstanceChoice,
pub backoff: Backoff,
}
impl Default for RetryPolicy {
fn default() -> Self {
Self {
max_attempts: 1,
on_retry: InstanceChoice::AvoidFailed,
backoff: Backoff::None,
}
}
}
impl RetryPolicy {
pub fn new() -> Self {
Self::default()
}
pub fn max_attempts(mut self, n: u32) -> Self {
self.max_attempts = n.max(1);
self
}
pub fn avoid_failed(mut self) -> Self {
self.on_retry = InstanceChoice::AvoidFailed;
self
}
pub fn any_instance(mut self) -> Self {
self.on_retry = InstanceChoice::Any;
self
}
pub fn backoff(mut self, backoff: Backoff) -> Self {
self.backoff = backoff;
self
}
pub(crate) fn delay(&self, attempt: u32) -> Option<Duration> {
self.backoff.delay(attempt)
}
}
#[derive(Clone, Copy)]
pub enum InstanceChoice {
AvoidFailed,
Any,
}
#[derive(Clone, Copy)]
pub enum Backoff {
None,
Fixed(Duration),
Exponential {
base: Duration,
factor: f64,
max: Duration,
},
}
impl Backoff {
pub(crate) fn delay(&self, attempt: u32) -> Option<Duration> {
match *self {
Backoff::None => None,
Backoff::Fixed(d) => Some(d),
Backoff::Exponential { base, factor, max } => {
let mult = factor.powi(attempt.saturating_sub(1) as i32);
Some(base.mul_f64(mult).min(max))
}
}
}
}