use std::time::{Duration, Instant};
use crate::errors::SdkError;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RecoveryPolicy {
pub max_attempts: u8,
pub budget: Duration,
}
impl Default for RecoveryPolicy {
fn default() -> Self {
Self {
max_attempts: 5,
budget: Duration::from_secs(30),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct RecoveryBudget {
policy: RecoveryPolicy,
started_at: Option<Instant>,
attempts: u8,
}
impl RecoveryBudget {
pub const fn new(policy: RecoveryPolicy) -> Self {
Self {
policy,
started_at: None,
attempts: 0,
}
}
pub const fn attempts(self) -> u8 {
self.attempts
}
pub fn begin(&mut self, now: Instant) {
self.started_at = Some(now);
self.attempts = 0;
}
pub fn next_attempt(&mut self, now: Instant) -> Result<u8, SdkError> {
let started = self.started_at.get_or_insert(now);
if self.attempts >= self.policy.max_attempts
|| now.duration_since(*started) >= self.policy.budget
{
return Err(SdkError::RecoveryExhausted);
}
self.attempts = self.attempts.saturating_add(1);
Ok(self.attempts)
}
pub fn reset(&mut self) {
self.started_at = None;
self.attempts = 0;
}
}