#![cfg_attr(
feature = "config",
doc = r##"
The RetryConfig struct can be used to retry an operation with a serializable retry config
that specifies an amount of retries and a random backoff interval.
```
# use retry_block::OperationResult;
# use retry_block::RetryConfig;
# use retry_block::delay::Fixed;
# use retry_block::retry;
let config = RetryConfig {
count: 1,
min_backoff: 100,
max_backoff: 300,
};
let mut collection = vec![1, 2, 3].into_iter();
let result = retry!(config, {
match collection.next() {
Some(n) if n == 3 => Ok("n is 3!"),
Some(_) => Err("n must be 3!"),
None => Err("n was never 3!"),
}
});
assert!(result.is_err());
```
"##
)]
#![cfg_attr(
feature = "random",
doc = r##"
Random jitter is applied by default to any delay strategy, but you can make it fixed using `exact`
or add random jitter to any delay strategy using the `jitter` function:
```
# use retry_block::retry_fn;
# use retry_block::OperationResult;
# use retry_block::delay::{Exponential, jitter};
# use std::time::Duration;
let mut collection = vec![1, 2, 3].into_iter();
let result = retry_fn(Exponential::exact(Duration::from_millis(10)).map(jitter).take(3), || {
match collection.next() {
Some(n) if n == 3 => Ok("n is 3!"),
Some(_) => Err("n must be 3!"),
None => Err("n was never 3!"),
}
});
assert!(result.is_ok());
```
"##
)]
use serde::Deserialize;
use std::time::Duration;
pub mod delay;
#[cfg(feature = "future")]
pub mod future;
mod r#macro;
pub mod persist;
pub use future::*;
#[derive(Debug, Deserialize, Clone)]
pub struct RetryConfig {
pub count: usize,
pub min_backoff: u64,
pub max_backoff: u64,
}
impl IntoIterator for RetryConfig {
type Item = Duration;
type IntoIter = std::iter::Take<delay::Range>;
fn into_iter(self) -> Self::IntoIter {
delay::Range::from_millis_inclusive(self.min_backoff, self.max_backoff).take(self.count)
}
}
#[derive(Debug)]
pub enum OperationResult<T, E> {
Ok(T),
Retry(E),
Err(E),
}
impl<T, E> From<Result<T, E>> for OperationResult<T, E> {
fn from(item: Result<T, E>) -> Self {
match item {
Ok(v) => OperationResult::Ok(v),
Err(e) => OperationResult::Retry(e),
}
}
}
pub fn retry_fn<D, O, OR, R, E>(durations: D, mut operation: O) -> Result<R, E>
where
D: IntoIterator<Item = Duration>,
O: FnMut() -> OR,
OR: Into<OperationResult<R, E>>,
{
retry!(durations, { operation() })
}