use std::time::Duration;
use tokio_retry::strategy::{jitter, ExponentialBackoff, FibonacciBackoff, FixedInterval};
#[derive(Clone, Debug)]
pub enum RetryStrategy {
ExponentialBackoff {
initial_millis: u64,
factor: u64,
max_delay_secs: u64,
},
FibonacciBackoff {
initial_millis: u64,
factor: u64,
max_delay_secs: u64,
},
FixedInterval {
interval_millis: u64,
},
}
impl Default for RetryStrategy {
fn default() -> Self {
RetryStrategy::ExponentialBackoff {
initial_millis: 100, factor: 2, max_delay_secs: 10,
}
}
}
impl RetryStrategy {
pub(crate) fn delay_iterator_with_jitter(
self,
max_retries: usize,
) -> impl Iterator<Item = Duration> + Clone {
self.into_delay_iterator().map(jitter).take(max_retries)
}
fn into_delay_iterator(self) -> RetryDelayIterator {
match self {
RetryStrategy::ExponentialBackoff {
initial_millis,
factor,
max_delay_secs,
} => RetryDelayIterator::ExponentialBackoff(
ExponentialBackoff::from_millis(initial_millis)
.factor(factor)
.max_delay(Duration::from_secs(max_delay_secs)),
),
RetryStrategy::FibonacciBackoff {
initial_millis,
factor,
max_delay_secs,
} => RetryDelayIterator::FibonacciBackoff(
FibonacciBackoff::from_millis(initial_millis)
.factor(factor)
.max_delay(Duration::from_secs(max_delay_secs)),
),
RetryStrategy::FixedInterval { interval_millis } => {
RetryDelayIterator::FixedInterval(FixedInterval::from_millis(interval_millis))
}
}
}
}
#[derive(Clone)]
enum RetryDelayIterator {
ExponentialBackoff(ExponentialBackoff),
FibonacciBackoff(FibonacciBackoff),
FixedInterval(FixedInterval),
}
impl Iterator for RetryDelayIterator {
type Item = Duration;
fn next(&mut self) -> Option<Self::Item> {
match self {
RetryDelayIterator::ExponentialBackoff(s) => s.next(),
RetryDelayIterator::FibonacciBackoff(s) => s.next(),
RetryDelayIterator::FixedInterval(s) => s.next(),
}
}
}