lago_client/retry.rs
1use std::time::Duration;
2
3/// Defines the retry behavior for failed requests
4///
5/// This enum controls how the client handles retry attempts when requests fail.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub enum RetryMode {
8 Off,
9 Standard,
10 Adaptive,
11}
12
13impl Default for RetryMode {
14 /// Returns the default retry mode (Standard)
15 ///
16 /// # Returns
17 /// `RetryMode::Standard` as the default retry behavior
18 fn default() -> Self {
19 RetryMode::Standard
20 }
21}
22
23/// Configuration settings for retry behavior
24///
25/// This struct contains all the parameters needed to configure how the client
26/// handles retry attempts, including timing, limits, and backoff strategies.
27#[derive(Debug, Clone)]
28pub struct RetryConfig {
29 pub(crate) mode: RetryMode,
30 pub(crate) max_attempts: u32,
31 pub(crate) initial_delay: Duration,
32 pub(crate) max_delay: Duration,
33 pub(crate) backoff_multiplier: f64,
34}
35
36impl RetryConfig {
37 /// Creates a new retry configuration with default settings
38 ///
39 /// # Returns
40 /// A new `RetryConfig` instance with default values
41 pub fn new() -> Self {
42 Self::default()
43 }
44
45 /// Creates a new retry configuration builder
46 ///
47 /// # Returns
48 /// A new `RetryConfigBuilder` instance for constructing custom retry settings
49 pub fn builder() -> RetryConfigBuilder {
50 RetryConfigBuilder::new()
51 }
52
53 /// Gets the retry mode
54 ///
55 /// # Returns
56 /// A reference to the current retry mode
57 pub fn mode(&self) -> &RetryMode {
58 &self.mode
59 }
60
61 /// Gets the maximum number of retry attempts
62 ///
63 /// # Returns
64 /// A reference to the maximum attempts setting
65 pub fn max_attempts(&self) -> &u32 {
66 &self.max_attempts
67 }
68
69 /// Gets the initial delay for retry attempts
70 ///
71 /// # Returns
72 /// A reference to the initial delay duration
73 pub fn initial_delay(&self) -> &Duration {
74 &self.initial_delay
75 }
76
77 /// Gets the maximum delay between retry attempts
78 ///
79 /// # Returns
80 /// A reference to the maximum delay duration
81 pub fn max_delay(&self) -> &Duration {
82 &self.max_delay
83 }
84
85 /// Calculates the delay duration for a specific retry attempt
86 ///
87 /// This method implements exponential backoff with a configurable multiplier
88 /// and enforces the maximum delay limit.
89 ///
90 /// # Arguments
91 /// * `attempt` - The attempt number (0-based)
92 ///
93 /// # Returns
94 /// The duration to wait before the next retry attempt
95 pub fn delay_for_attempt(&self, attempt: u32) -> Duration {
96 if self.mode == RetryMode::Off {
97 return Duration::from_secs(0);
98 }
99
100 let delay_secs =
101 self.initial_delay.as_secs_f64() * self.backoff_multiplier.powi(attempt as i32);
102
103 let delay = Duration::from_secs_f64(delay_secs);
104
105 if delay > self.max_delay {
106 self.max_delay
107 } else {
108 delay
109 }
110 }
111}
112
113impl Default for RetryConfig {
114 /// Creates a default retry configuration
115 ///
116 /// By default, retries are disabled (mode is Off) with conservative settings
117 /// that can be overridden when building a custom configuration.
118 fn default() -> Self {
119 Self {
120 mode: RetryMode::Off,
121 max_attempts: 1,
122 initial_delay: Duration::from_millis(100),
123 max_delay: Duration::from_secs(30),
124 backoff_multiplier: 2.0,
125 }
126 }
127}
128
129/// Builder for creating customized retry configuration instances
130///
131/// This builder allows you to configure various aspects of retry behavior
132/// such as retry mode, maximum attempts, delays, and backoff multipliers.
133#[derive(Debug, Clone)]
134pub struct RetryConfigBuilder {
135 mode: RetryMode,
136 max_attempts: u32,
137 initial_delay: Duration,
138 max_delay: Duration,
139 backoff_multiplier: f64,
140}
141
142impl RetryConfigBuilder {
143 /// Creates a new retry configuration builder with sensible defaults
144 ///
145 /// # Returns
146 /// A new `RetryConfigBuilder` instance with default retry settings
147 pub fn new() -> Self {
148 Self {
149 mode: RetryMode::Standard,
150 max_attempts: 3,
151 initial_delay: Duration::from_millis(100),
152 max_delay: Duration::from_secs(30),
153 backoff_multiplier: 2.0,
154 }
155 }
156
157 /// Sets the retry mode
158 ///
159 /// # Arguments
160 /// * `mode` - The retry mode to use
161 ///
162 /// # Returns
163 /// The builder instance for method chaining
164 pub fn mode(mut self, mode: RetryMode) -> Self {
165 self.mode = mode;
166 self
167 }
168
169 /// Sets the maximum number of retry attempts
170 ///
171 /// # Arguments
172 /// * `max_attempts` - The maximum number of retry attempts
173 ///
174 /// # Returns
175 /// The builder instance for method chaining
176 pub fn max_attempts(mut self, max_attempts: u32) -> Self {
177 self.max_attempts = max_attempts;
178 self
179 }
180
181 /// Sets the initial delay for retry attempts
182 ///
183 /// # Arguments
184 /// * `delay` - The initial delay duration
185 ///
186 /// # Returns
187 /// The builder instance for method chaining
188 pub fn initial_delay(mut self, delay: Duration) -> Self {
189 self.initial_delay = delay;
190 self
191 }
192
193 /// Sets the maximum delay between retry attempts
194 ///
195 /// # Arguments
196 /// * `delay` - The maximum delay duration
197 ///
198 /// # Returns
199 /// The builder instance for method chaining
200 pub fn max_delay(mut self, delay: Duration) -> Self {
201 self.max_delay = delay;
202 self
203 }
204
205 /// Sets the backoff multiplier for exponential backoff
206 ///
207 /// # Arguments
208 /// * `multiplier` - The multiplier to apply to delays between attempts
209 ///
210 /// # Returns
211 /// The builder instance for method chaining
212 pub fn backoff_multiplier(mut self, multiplier: f64) -> Self {
213 self.backoff_multiplier = multiplier;
214 self
215 }
216
217 /// Builds the final retry configuration instance
218 ///
219 /// # Returns
220 /// A new `RetryConfig` instance with the specified settings
221 pub fn build(self) -> RetryConfig {
222 RetryConfig {
223 mode: self.mode,
224 max_attempts: self.max_attempts,
225 initial_delay: self.initial_delay,
226 max_delay: self.max_delay,
227 backoff_multiplier: self.backoff_multiplier,
228 }
229 }
230}
231
232impl Default for RetryConfigBuilder {
233 /// Creates a default retry configuration builder
234 ///
235 /// This is equivalent to calling `RetryConfigBuilder::new()`.
236 fn default() -> Self {
237 Self::new()
238 }
239}