#![allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(dead_code)]
pub enum RetryResult {
Retry,
GiveUp,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct RetryPolicy {
max_retries: u32,
base_delay_ms: u64,
attempt: u32,
}
#[allow(dead_code)]
pub fn new_retry_policy(max_retries: u32, base_delay_ms: u64) -> RetryPolicy {
RetryPolicy {
max_retries,
base_delay_ms,
attempt: 0,
}
}
#[allow(dead_code)]
pub fn should_retry(policy: &mut RetryPolicy) -> RetryResult {
if policy.attempt < policy.max_retries {
policy.attempt += 1;
RetryResult::Retry
} else {
RetryResult::GiveUp
}
}
#[allow(dead_code)]
pub fn retry_count(policy: &RetryPolicy) -> u32 {
policy.attempt
}
#[allow(dead_code)]
pub fn max_retries(policy: &RetryPolicy) -> u32 {
policy.max_retries
}
#[allow(dead_code)]
pub fn retry_delay_ms(policy: &RetryPolicy) -> u64 {
policy.base_delay_ms
}
#[allow(dead_code)]
pub fn retry_with_backoff(policy: &RetryPolicy) -> u64 {
if policy.attempt == 0 {
return 0;
}
policy
.base_delay_ms
.saturating_mul(1u64 << (policy.attempt - 1).min(10))
}
#[allow(dead_code)]
pub fn reset_retry(policy: &mut RetryPolicy) {
policy.attempt = 0;
}
#[allow(dead_code)]
pub fn retry_exhausted(policy: &RetryPolicy) -> bool {
policy.attempt >= policy.max_retries
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_retry_policy() {
let p = new_retry_policy(3, 100);
assert_eq!(max_retries(&p), 3);
assert_eq!(retry_delay_ms(&p), 100);
assert_eq!(retry_count(&p), 0);
}
#[test]
fn test_should_retry() {
let mut p = new_retry_policy(2, 50);
assert_eq!(should_retry(&mut p), RetryResult::Retry);
assert_eq!(should_retry(&mut p), RetryResult::Retry);
assert_eq!(should_retry(&mut p), RetryResult::GiveUp);
}
#[test]
fn test_retry_exhausted() {
let mut p = new_retry_policy(1, 0);
assert!(!retry_exhausted(&p));
should_retry(&mut p);
assert!(retry_exhausted(&p));
}
#[test]
fn test_retry_count() {
let mut p = new_retry_policy(5, 10);
should_retry(&mut p);
should_retry(&mut p);
assert_eq!(retry_count(&p), 2);
}
#[test]
fn test_reset_retry() {
let mut p = new_retry_policy(3, 10);
should_retry(&mut p);
should_retry(&mut p);
reset_retry(&mut p);
assert_eq!(retry_count(&p), 0);
}
#[test]
fn test_retry_with_backoff() {
let mut p = new_retry_policy(5, 100);
assert_eq!(retry_with_backoff(&p), 0);
should_retry(&mut p);
assert_eq!(retry_with_backoff(&p), 100);
should_retry(&mut p);
assert_eq!(retry_with_backoff(&p), 200);
should_retry(&mut p);
assert_eq!(retry_with_backoff(&p), 400);
}
#[test]
fn test_zero_retries() {
let mut p = new_retry_policy(0, 0);
assert_eq!(should_retry(&mut p), RetryResult::GiveUp);
}
#[test]
fn test_max_retries_accessor() {
let p = new_retry_policy(7, 0);
assert_eq!(max_retries(&p), 7);
}
}