use tokio::time::Duration;
pub(crate) const MAX_RETRIES: u32 = 4;
pub(crate) const BASE_BACKOFF: Duration = Duration::from_millis(500);
pub(crate) const MAX_BACKOFF: Duration = Duration::from_secs(30);
pub(crate) fn backoff_base(attempt: u32) -> Duration {
BASE_BACKOFF
.saturating_mul(1u32 << attempt.min(20))
.min(MAX_BACKOFF)
}
fn jitter(span: Duration) -> Duration {
if span.is_zero() {
return Duration::ZERO;
}
let nanos = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.subsec_nanos())
.unwrap_or(0);
span.mul_f64(nanos as f64 / 1_000_000_000.0)
}
pub(crate) fn backoff_delay(attempt: u32) -> Duration {
let half = backoff_base(attempt) / 2;
half + jitter(half)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn backoff_base_grows_and_caps() {
assert_eq!(backoff_base(0), BASE_BACKOFF);
assert_eq!(backoff_base(1), BASE_BACKOFF * 2);
assert_eq!(backoff_base(2), BASE_BACKOFF * 4);
assert_eq!(backoff_base(30), MAX_BACKOFF);
}
}