use core::future::Future;
use core::time::Duration;
use crate::error::RetryError;
use crate::policy::RetryPolicy;
pub fn retry<T, E, Op, ShouldRetry>(
policy: &RetryPolicy,
op: Op,
should_retry: ShouldRetry,
) -> Result<T, RetryError<E>>
where
Op: FnMut() -> Result<T, E>,
ShouldRetry: FnMut(&E) -> bool,
{
retry_with_sleep(policy, op, should_retry, |_delay| {})
}
pub fn retry_with_sleep<T, E, Op, ShouldRetry, Sleep>(
policy: &RetryPolicy,
mut op: Op,
mut should_retry: ShouldRetry,
mut sleep: Sleep,
) -> Result<T, RetryError<E>>
where
Op: FnMut() -> Result<T, E>,
ShouldRetry: FnMut(&E) -> bool,
Sleep: FnMut(Duration),
{
let mut attempt: u32 = 0;
loop {
attempt += 1;
match op() {
Ok(value) => return Ok(value),
Err(error) => {
if attempt >= policy.max_attempts() || !should_retry(&error) {
return Err(RetryError::Exhausted {
attempts: attempt,
last_error: error,
});
}
sleep(policy.delay_before_retry(attempt));
}
}
}
}
pub async fn retry_async<T, E, Op, Fut, ShouldRetry, Sleep, SleepFut>(
policy: &RetryPolicy,
mut op: Op,
mut should_retry: ShouldRetry,
mut sleep: Sleep,
) -> Result<T, RetryError<E>>
where
Op: FnMut() -> Fut,
Fut: Future<Output = Result<T, E>>,
ShouldRetry: FnMut(&E) -> bool,
Sleep: FnMut(Duration) -> SleepFut,
SleepFut: Future<Output = ()>,
{
let mut attempt: u32 = 0;
loop {
attempt += 1;
match op().await {
Ok(value) => return Ok(value),
Err(error) => {
if attempt >= policy.max_attempts() || !should_retry(&error) {
return Err(RetryError::Exhausted {
attempts: attempt,
last_error: error,
});
}
sleep(policy.delay_before_retry(attempt)).await;
}
}
}
}