babelforce_manager_sdk/
retry.rs1use std::time::Duration;
2
3#[derive(Clone, Debug)]
6pub struct RetryPolicy {
7 pub max_retries: u32,
9 pub base_delay: Duration,
11 pub max_delay: Duration,
13}
14
15impl Default for RetryPolicy {
16 fn default() -> Self {
17 Self {
18 max_retries: 2,
19 base_delay: Duration::from_millis(250),
20 max_delay: Duration::from_secs(10),
21 }
22 }
23}
24
25impl RetryPolicy {
26 pub fn disabled() -> Self {
28 Self {
29 max_retries: 0,
30 ..Self::default()
31 }
32 }
33}
34
35pub(crate) trait Transient {
38 fn transient(&self, idempotent: bool) -> bool;
39}
40
41pub(crate) async fn with_retry<F, Fut, R, E>(
44 policy: &RetryPolicy,
45 idempotent: bool,
46 mut f: F,
47) -> Result<R, E>
48where
49 F: FnMut() -> Fut,
50 Fut: std::future::Future<Output = Result<R, E>>,
51 E: Transient,
52{
53 let mut attempt: u32 = 0;
54 loop {
55 match f().await {
56 Ok(r) => return Ok(r),
57 Err(e) => {
58 if attempt >= policy.max_retries || !e.transient(idempotent) {
59 return Err(e);
60 }
61 let factor = 1u32.checked_shl(attempt.min(16)).unwrap_or(u32::MAX);
62 let delay = policy
63 .base_delay
64 .saturating_mul(factor)
65 .min(policy.max_delay);
66 tokio::time::sleep(delay).await;
67 attempt += 1;
68 }
69 }
70 }
71}