mutant_lib/utils/
retry.rs

1use crate::error::Error;
2use std::future::Future;
3use std::time::Duration;
4use tokio_retry::{
5    strategy::{jitter, ExponentialBackoff},
6    RetryIf,
7};
8
9/// Standard retry strategy: Exponential backoff starting at 100ms, 5 attempts, with jitter.
10pub fn standard_retry_strategy() -> impl Iterator<Item = Duration> {
11    ExponentialBackoff::from_millis(100)
12        .max_delay(Duration::from_secs(5))
13        .map(jitter)
14        .take(5)
15}
16
17/// Executes an asynchronous action with a standard retry strategy.
18///
19/// # Arguments
20///
21/// * `action_description` - A string describing the action for logging purposes.
22/// * `action` - An async closure representing the action to perform. Must be `Fn`.
23/// * `retry_if` - A closure that takes a reference to the error and returns true if the action should be retried.
24///
25/// # Returns
26///
27/// Returns the result of the action if successful within the retry attempts,
28/// otherwise returns the last error encountered.
29pub async fn retry_operation<F, Fut, T, E, R>(
30    _action_description: &str,
31    action: F,
32    retry_if: R,
33) -> Result<T, E>
34where
35    F: Fn() -> Fut,
36    Fut: Future<Output = Result<T, E>>,
37    E: std::fmt::Display + From<Error> + std::fmt::Debug, // Add Debug constraint for logging
38    R: FnMut(&E) -> bool,
39{
40    let strategy = standard_retry_strategy();
41    let result = RetryIf::spawn(strategy, action, retry_if).await;
42
43    result
44}