use std::time::Duration;
#[derive(Debug, Clone)]
pub struct RetryConfig {
pub(crate) max_attempts: u8,
pub(crate) initial_backoff: Duration,
pub(crate) max_backoff: Duration,
pub(crate) reduce_chunk_on_retry: bool,
pub(crate) min_sectors_per_read: u32,
}
impl RetryConfig {
pub fn with_max_attempts(mut self, attempts: u8) -> Self {
self.max_attempts = attempts.max(1);
self
}
pub fn with_initial_backoff(mut self, backoff: Duration) -> Self {
self.initial_backoff = backoff;
self
}
pub fn with_max_backoff(mut self, backoff: Duration) -> Self {
self.max_backoff = backoff;
self
}
pub fn with_chunk_reduction(mut self, enabled: bool) -> Self {
self.reduce_chunk_on_retry = enabled;
self
}
pub fn with_min_sectors_per_read(mut self, sectors: u32) -> Self {
self.min_sectors_per_read = sectors.max(1);
self
}
}
impl Default for RetryConfig {
fn default() -> Self {
Self {
max_attempts: 4,
initial_backoff: Duration::from_millis(20),
max_backoff: Duration::from_millis(300),
reduce_chunk_on_retry: true,
min_sectors_per_read: 1,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_policy_matches_documented_values() {
let config = RetryConfig::default();
assert_eq!(config.max_attempts, 4);
assert_eq!(config.initial_backoff, Duration::from_millis(20));
assert_eq!(config.max_backoff, Duration::from_millis(300));
assert!(config.reduce_chunk_on_retry);
assert_eq!(config.min_sectors_per_read, 1);
}
#[test]
fn builders_override_and_normalize_values() {
let config = RetryConfig::default()
.with_max_attempts(0)
.with_initial_backoff(Duration::from_millis(50))
.with_max_backoff(Duration::from_secs(1))
.with_chunk_reduction(false)
.with_min_sectors_per_read(0);
assert_eq!(config.max_attempts, 1);
assert_eq!(config.initial_backoff, Duration::from_millis(50));
assert_eq!(config.max_backoff, Duration::from_secs(1));
assert!(!config.reduce_chunk_on_retry);
assert_eq!(config.min_sectors_per_read, 1);
}
}