mssql_client/config/
types.rs1use std::time::Duration;
4
5#[derive(Debug, Clone)]
10pub struct RedirectConfig {
11 pub max_redirects: u8,
13 pub follow_redirects: bool,
15}
16
17impl Default for RedirectConfig {
18 fn default() -> Self {
19 Self {
20 max_redirects: 2,
21 follow_redirects: true,
22 }
23 }
24}
25
26impl RedirectConfig {
27 #[must_use]
29 pub fn new() -> Self {
30 Self::default()
31 }
32
33 #[must_use]
35 pub fn max_redirects(mut self, max: u8) -> Self {
36 self.max_redirects = max;
37 self
38 }
39
40 #[must_use]
42 pub fn follow_redirects(mut self, follow: bool) -> Self {
43 self.follow_redirects = follow;
44 self
45 }
46
47 #[must_use]
52 pub fn no_follow() -> Self {
53 Self {
54 max_redirects: 0,
55 follow_redirects: false,
56 }
57 }
58}
59
60#[derive(Debug, Clone)]
65pub struct TimeoutConfig {
66 pub connect_timeout: Duration,
68 pub tls_timeout: Duration,
70 pub login_timeout: Duration,
72 pub command_timeout: Duration,
74 pub idle_timeout: Duration,
76 pub keepalive_interval: Option<Duration>,
78}
79
80impl Default for TimeoutConfig {
81 fn default() -> Self {
82 Self {
83 connect_timeout: Duration::from_secs(15),
84 tls_timeout: Duration::from_secs(10),
85 login_timeout: Duration::from_secs(30),
86 command_timeout: Duration::from_secs(30),
87 idle_timeout: Duration::from_secs(300),
88 keepalive_interval: Some(Duration::from_secs(30)),
89 }
90 }
91}
92
93impl TimeoutConfig {
94 #[must_use]
96 pub fn new() -> Self {
97 Self::default()
98 }
99
100 #[must_use]
102 pub fn connect_timeout(mut self, timeout: Duration) -> Self {
103 self.connect_timeout = timeout;
104 self
105 }
106
107 #[must_use]
109 pub fn tls_timeout(mut self, timeout: Duration) -> Self {
110 self.tls_timeout = timeout;
111 self
112 }
113
114 #[must_use]
116 pub fn login_timeout(mut self, timeout: Duration) -> Self {
117 self.login_timeout = timeout;
118 self
119 }
120
121 #[must_use]
123 pub fn command_timeout(mut self, timeout: Duration) -> Self {
124 self.command_timeout = timeout;
125 self
126 }
127
128 #[must_use]
130 pub fn idle_timeout(mut self, timeout: Duration) -> Self {
131 self.idle_timeout = timeout;
132 self
133 }
134
135 #[must_use]
137 pub fn keepalive_interval(mut self, interval: Option<Duration>) -> Self {
138 self.keepalive_interval = interval;
139 self
140 }
141
142 #[must_use]
144 pub fn no_keepalive(mut self) -> Self {
145 self.keepalive_interval = None;
146 self
147 }
148
149 #[must_use]
151 pub fn total_connect_timeout(&self) -> Duration {
152 self.connect_timeout + self.tls_timeout + self.login_timeout
153 }
154}
155
156#[derive(Debug, Clone)]
161pub struct RetryPolicy {
162 pub max_retries: u32,
164 pub initial_backoff: Duration,
166 pub max_backoff: Duration,
168 pub backoff_multiplier: f64,
170 pub jitter: bool,
172}
173
174impl Default for RetryPolicy {
175 fn default() -> Self {
176 Self {
177 max_retries: 3,
178 initial_backoff: Duration::from_millis(100),
179 max_backoff: Duration::from_secs(30),
180 backoff_multiplier: 2.0,
181 jitter: true,
182 }
183 }
184}
185
186impl RetryPolicy {
187 #[must_use]
189 pub fn new() -> Self {
190 Self::default()
191 }
192
193 #[must_use]
195 pub fn max_retries(mut self, max: u32) -> Self {
196 self.max_retries = max;
197 self
198 }
199
200 #[must_use]
202 pub fn initial_backoff(mut self, backoff: Duration) -> Self {
203 self.initial_backoff = backoff;
204 self
205 }
206
207 #[must_use]
209 pub fn max_backoff(mut self, backoff: Duration) -> Self {
210 self.max_backoff = backoff;
211 self
212 }
213
214 #[must_use]
216 pub fn backoff_multiplier(mut self, multiplier: f64) -> Self {
217 self.backoff_multiplier = multiplier;
218 self
219 }
220
221 #[must_use]
223 pub fn jitter(mut self, enabled: bool) -> Self {
224 self.jitter = enabled;
225 self
226 }
227
228 #[must_use]
230 pub fn no_retry() -> Self {
231 Self {
232 max_retries: 0,
233 ..Self::default()
234 }
235 }
236
237 #[must_use]
241 pub fn backoff_for_attempt(&self, attempt: u32) -> Duration {
242 if attempt == 0 {
243 return Duration::ZERO;
244 }
245
246 let base = self.initial_backoff.as_millis() as f64
247 * self
248 .backoff_multiplier
249 .powi(attempt.saturating_sub(1) as i32);
250 let capped = base.min(self.max_backoff.as_millis() as f64);
251
252 if self.jitter {
253 Duration::from_millis(capped as u64)
256 } else {
257 Duration::from_millis(capped as u64)
258 }
259 }
260
261 #[must_use]
263 pub fn should_retry(&self, attempt: u32) -> bool {
264 attempt < self.max_retries
265 }
266}