1use std::time::Duration;
4
5#[derive(Debug, Clone, PartialEq)]
7pub struct SupervisionConfig {
8 pub max_attempts: Option<u32>,
11
12 pub initial_delay: Duration,
15
16 pub backoff_multiplier: f64,
19
20 pub max_delay: Duration,
23}
24
25impl SupervisionConfig {
26 pub fn next_delay(&self, attempt: u32) -> Duration {
30 if attempt == 0 {
31 return self.initial_delay;
32 }
33 let exp = ((attempt - 1) as i32).min(63);
35 let exp_value = self.backoff_multiplier.powi(exp);
36 let millis = (self.initial_delay.as_millis() as f64 * exp_value) as u128;
37 let delay = Duration::from_millis(millis as u64);
38 delay.min(self.max_delay)
39 }
40}
41
42impl Default for SupervisionConfig {
43 fn default() -> Self {
44 Self {
45 max_attempts: Some(5),
46 initial_delay: Duration::from_secs(1),
47 backoff_multiplier: 2.0,
48 max_delay: Duration::from_secs(60),
49 }
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use std::time::Duration;
57
58 #[test]
59 fn test_supervision_config_defaults() {
60 let cfg = SupervisionConfig::default();
61 assert_eq!(cfg.max_attempts, Some(5));
62 assert_eq!(cfg.initial_delay, Duration::from_secs(1));
63 assert_eq!(cfg.backoff_multiplier, 2.0);
64 assert_eq!(cfg.max_delay, Duration::from_secs(60));
65 }
66
67 #[test]
68 fn test_supervision_config_infinite() {
69 let cfg = SupervisionConfig {
70 max_attempts: None,
71 ..Default::default()
72 };
73 assert!(cfg.max_attempts.is_none());
74 }
75
76 #[test]
77 fn test_supervision_config_next_delay_growth() {
78 let cfg = SupervisionConfig::default();
79 let d1 = cfg.next_delay(1); let d2 = cfg.next_delay(2); let d3 = cfg.next_delay(3); assert_eq!(d1, Duration::from_secs(1));
83 assert_eq!(d2, Duration::from_secs(2));
84 assert_eq!(d3, Duration::from_secs(4));
85 }
86
87 #[test]
88 fn test_supervision_config_next_delay_capped() {
89 let cfg = SupervisionConfig {
90 max_delay: Duration::from_secs(5),
91 ..Default::default()
92 };
93 let d = cfg.next_delay(10); assert_eq!(d, Duration::from_secs(5));
95 }
96
97 #[test]
98 fn test_next_delay_attempt_zero_returns_initial_delay() {
99 let cfg = SupervisionConfig::default();
100 let d = cfg.next_delay(0);
101 assert_eq!(d, cfg.initial_delay);
102 }
103}