prism3_retry/
default_config.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Default Retry Configuration Implementation
10//!
11//! Provides a default retry configuration implementation based on `Config`.
12//!
13//! # Author
14//!
15//! Haixing Hu
16
17use super::config::RetryConfig;
18use super::delay_strategy::RetryDelayStrategy;
19use prism3_config::{Config, Configurable};
20use std::time::Duration;
21
22/// Default retry configuration implementation
23///
24/// Uses `Config` to store all configuration values, implementing both the `RetryConfig` trait and the `Configurable` trait.
25///
26/// # Author
27///
28/// Haixing Hu
29#[derive(Debug, Clone)]
30pub struct DefaultRetryConfig {
31    config: Config,
32}
33
34impl DefaultRetryConfig {
35    /// Create a new `DefaultRetryConfig` instance with default configuration
36    pub fn new() -> Self {
37        Self {
38            config: Config::new(),
39        }
40    }
41
42    /// Create a new `DefaultRetryConfig` instance with the specified configuration
43    pub fn with_config(config: Config) -> Self {
44        Self { config }
45    }
46
47    /// Get delay strategy from configuration
48    fn get_delay_strategy_from_config(&self) -> RetryDelayStrategy {
49        let strategy_name = self
50            .config
51            .get_string_or(Self::KEY_DELAY_STRATEGY, "EXPONENTIAL_BACKOFF");
52
53        match strategy_name.as_str() {
54            "NONE" => RetryDelayStrategy::none(),
55            "FIXED" => {
56                let delay_millis = self
57                    .config
58                    .get_or(Self::KEY_FIXED_DELAY, Self::DEFAULT_FIXED_DELAY_MILLIS);
59                RetryDelayStrategy::fixed(Duration::from_millis(delay_millis))
60            }
61            "RANDOM" => {
62                let min_delay_millis = self.config.get_or(
63                    Self::KEY_RANDOM_MIN_DELAY,
64                    Self::DEFAULT_RANDOM_MIN_DELAY_MILLIS,
65                );
66                let max_delay_millis = self.config.get_or(
67                    Self::KEY_RANDOM_MAX_DELAY,
68                    Self::DEFAULT_RANDOM_MAX_DELAY_MILLIS,
69                );
70                RetryDelayStrategy::random(
71                    Duration::from_millis(min_delay_millis),
72                    Duration::from_millis(max_delay_millis),
73                )
74            }
75            "EXPONENTIAL_BACKOFF" => {
76                let initial_delay_millis = self.config.get_or(
77                    Self::KEY_BACKOFF_INITIAL_DELAY,
78                    Self::DEFAULT_BACKOFF_INITIAL_DELAY_MILLIS,
79                );
80                let max_delay_millis = self.config.get_or(
81                    Self::KEY_BACKOFF_MAX_DELAY,
82                    Self::DEFAULT_BACKOFF_MAX_DELAY_MILLIS,
83                );
84                let multiplier = self.config.get_or(
85                    Self::KEY_BACKOFF_MULTIPLIER,
86                    Self::DEFAULT_BACKOFF_MULTIPLIER,
87                );
88                RetryDelayStrategy::exponential_backoff(
89                    Duration::from_millis(initial_delay_millis),
90                    Duration::from_millis(max_delay_millis),
91                    multiplier,
92                )
93            }
94            _ => Self::DEFAULT_DELAY_STRATEGY,
95        }
96    }
97
98    /// Save delay strategy to configuration
99    fn set_delay_strategy_to_config(&mut self, strategy: &RetryDelayStrategy) {
100        match strategy {
101            RetryDelayStrategy::None => {
102                self.config.set(Self::KEY_DELAY_STRATEGY, "NONE").unwrap();
103            }
104            RetryDelayStrategy::Fixed { delay } => {
105                self.config.set(Self::KEY_DELAY_STRATEGY, "FIXED").unwrap();
106                self.config
107                    .set(Self::KEY_FIXED_DELAY, delay.as_millis() as u64)
108                    .unwrap();
109            }
110            RetryDelayStrategy::Random {
111                min_delay,
112                max_delay,
113            } => {
114                self.config.set(Self::KEY_DELAY_STRATEGY, "RANDOM").unwrap();
115                self.config
116                    .set(Self::KEY_RANDOM_MIN_DELAY, min_delay.as_millis() as u64)
117                    .unwrap();
118                self.config
119                    .set(Self::KEY_RANDOM_MAX_DELAY, max_delay.as_millis() as u64)
120                    .unwrap();
121            }
122            RetryDelayStrategy::ExponentialBackoff {
123                initial_delay,
124                max_delay,
125                multiplier,
126            } => {
127                self.config
128                    .set(Self::KEY_DELAY_STRATEGY, "EXPONENTIAL_BACKOFF")
129                    .unwrap();
130                self.config
131                    .set(
132                        Self::KEY_BACKOFF_INITIAL_DELAY,
133                        initial_delay.as_millis() as u64,
134                    )
135                    .unwrap();
136                self.config
137                    .set(Self::KEY_BACKOFF_MAX_DELAY, max_delay.as_millis() as u64)
138                    .unwrap();
139                self.config
140                    .set(Self::KEY_BACKOFF_MULTIPLIER, *multiplier)
141                    .unwrap();
142            }
143        }
144    }
145}
146
147impl Default for DefaultRetryConfig {
148    fn default() -> Self {
149        Self::new()
150    }
151}
152
153impl Configurable for DefaultRetryConfig {
154    fn config(&self) -> &Config {
155        &self.config
156    }
157
158    fn config_mut(&mut self) -> &mut Config {
159        &mut self.config
160    }
161
162    fn set_config(&mut self, config: Config) {
163        self.config = config;
164        self.on_config_changed();
165    }
166
167    fn on_config_changed(&mut self) {
168        // Default implementation is empty, subclasses can override this method
169    }
170}
171
172impl RetryConfig for DefaultRetryConfig {
173    fn max_attempts(&self) -> u32 {
174        self.config
175            .get_or(Self::KEY_MAX_ATTEMPTS, Self::DEFAULT_MAX_ATTEMPTS)
176    }
177
178    fn set_max_attempts(&mut self, max_attempts: u32) -> &mut Self {
179        self.config
180            .set(Self::KEY_MAX_ATTEMPTS, max_attempts)
181            .unwrap();
182        self
183    }
184
185    fn max_duration(&self) -> Option<Duration> {
186        let millis = self
187            .config
188            .get_or(Self::KEY_MAX_DURATION, Self::DEFAULT_MAX_DURATION_MILLIS);
189        if millis == 0 {
190            None
191        } else {
192            Some(Duration::from_millis(millis))
193        }
194    }
195
196    fn set_max_duration(&mut self, max_duration: Option<Duration>) -> &mut Self {
197        match max_duration {
198            None => self.config.set(Self::KEY_MAX_DURATION, 0u64).unwrap(),
199            Some(duration) => self
200                .config
201                .set(Self::KEY_MAX_DURATION, duration.as_millis() as u64)
202                .unwrap(),
203        }
204        self
205    }
206
207    fn operation_timeout(&self) -> Option<Duration> {
208        let millis = self.config.get_or(
209            Self::KEY_OPERATION_TIMEOUT,
210            Self::DEFAULT_OPERATION_TIMEOUT_MILLIS,
211        );
212        if millis == 0 {
213            None
214        } else {
215            Some(Duration::from_millis(millis))
216        }
217    }
218
219    fn set_operation_timeout(&mut self, timeout: Option<Duration>) -> &mut Self {
220        match timeout {
221            None => self.config.set(Self::KEY_OPERATION_TIMEOUT, 0u64).unwrap(),
222            Some(duration) => self
223                .config
224                .set(Self::KEY_OPERATION_TIMEOUT, duration.as_millis() as u64)
225                .unwrap(),
226        }
227        self
228    }
229
230    fn delay_strategy(&self) -> RetryDelayStrategy {
231        self.get_delay_strategy_from_config()
232    }
233
234    fn set_delay_strategy(&mut self, delay_strategy: RetryDelayStrategy) -> &mut Self {
235        self.set_delay_strategy_to_config(&delay_strategy);
236        self
237    }
238
239    fn jitter_factor(&self) -> f64 {
240        self.config
241            .get_or(Self::KEY_JITTER_FACTOR, Self::DEFAULT_JITTER_FACTOR)
242    }
243
244    fn set_jitter_factor(&mut self, jitter_factor: f64) -> &mut Self {
245        self.config
246            .set(Self::KEY_JITTER_FACTOR, jitter_factor)
247            .unwrap();
248        self
249    }
250}