ave_actors_actor/
supervision.rs1use std::{collections::VecDeque, fmt::Debug, time::Duration};
4
5pub trait RetryStrategy: Debug + Send + Sync {
11 fn max_retries(&self) -> usize;
13
14 fn next_backoff(&mut self) -> Option<Duration>;
16}
17
18#[derive(Debug, Clone)]
23pub enum SupervisionStrategy {
24 Stop,
26 Retry(Strategy),
28}
29
30#[derive(Debug, Clone)]
32pub enum Strategy {
33 NoInterval(NoIntervalStrategy),
35 FixedInterval(FixedIntervalStrategy),
37 CustomIntervalStrategy(CustomIntervalStrategy),
39}
40
41impl RetryStrategy for Strategy {
42 fn max_retries(&self) -> usize {
43 match self {
44 Self::NoInterval(strategy) => strategy.max_retries(),
45 Self::FixedInterval(strategy) => strategy.max_retries(),
46 Self::CustomIntervalStrategy(strategy) => strategy.max_retries(),
47 }
48 }
49
50 fn next_backoff(&mut self) -> Option<Duration> {
51 match self {
52 Self::NoInterval(strategy) => strategy.next_backoff(),
53 Self::FixedInterval(strategy) => strategy.next_backoff(),
54 Self::CustomIntervalStrategy(strategy) => strategy.next_backoff(),
55 }
56 }
57}
58
59impl Default for Strategy {
60 fn default() -> Self {
61 Self::NoInterval(NoIntervalStrategy::default())
62 }
63}
64
65#[derive(Debug, Default, Clone)]
67pub struct NoIntervalStrategy {
68 max_retries: usize,
70}
71
72impl NoIntervalStrategy {
73 pub const fn new(max_retries: usize) -> Self {
75 Self { max_retries }
76 }
77}
78
79impl RetryStrategy for NoIntervalStrategy {
80 fn max_retries(&self) -> usize {
81 self.max_retries
82 }
83
84 fn next_backoff(&mut self) -> Option<Duration> {
85 None
86 }
87}
88
89#[derive(Debug, Default, Clone)]
91pub struct FixedIntervalStrategy {
92 max_retries: usize,
94 duration: Duration,
96}
97
98impl FixedIntervalStrategy {
99 pub const fn new(max_retries: usize, duration: Duration) -> Self {
101 Self {
102 max_retries,
103 duration,
104 }
105 }
106}
107
108impl RetryStrategy for FixedIntervalStrategy {
109 fn max_retries(&self) -> usize {
110 self.max_retries
111 }
112
113 fn next_backoff(&mut self) -> Option<Duration> {
114 Some(self.duration)
115 }
116}
117
118#[derive(Debug, Default, Clone)]
123pub struct CustomIntervalStrategy {
124 durations: VecDeque<Duration>,
127 max_retries: usize,
129}
130
131impl CustomIntervalStrategy {
132 pub fn new(durations: VecDeque<Duration>) -> Self {
134 let max_retries = durations.len();
135 Self {
136 durations,
137 max_retries,
138 }
139 }
140}
141
142impl RetryStrategy for CustomIntervalStrategy {
143 fn max_retries(&self) -> usize {
144 self.max_retries
145 }
146
147 fn next_backoff(&mut self) -> Option<Duration> {
148 self.durations.pop_front()
149 }
150}
151
152#[cfg(test)]
153mod tests {
154
155 use super::*;
156
157 #[test]
158 fn test_no_interval_strategy() {
159 let mut strategy = NoIntervalStrategy::new(3);
160 assert_eq!(strategy.max_retries(), 3);
161 assert_eq!(strategy.next_backoff(), None);
162 }
163
164 #[test]
165 fn test_fixed_interval_strategy() {
166 let mut strategy =
167 FixedIntervalStrategy::new(3, Duration::from_secs(1));
168 assert_eq!(strategy.max_retries(), 3);
169 assert_eq!(strategy.next_backoff(), Some(Duration::from_secs(1)));
170 }
171
172 #[test]
173 fn test_exponential_custom_strategy() {
174 let mut strategy = CustomIntervalStrategy::new(VecDeque::from([
175 Duration::from_secs(1),
176 Duration::from_secs(2),
177 Duration::from_secs(3),
178 ]));
179 assert_eq!(strategy.max_retries(), 3);
180 assert!(strategy.next_backoff().is_some());
181 assert!(strategy.next_backoff().is_some());
182 assert!(strategy.next_backoff().is_some());
183 assert!(strategy.next_backoff().is_none());
184 }
185}