rust_rabbit/
config.rs

1use serde::{Deserialize, Serialize};
2use std::time::Duration;
3
4/// Main configuration for RabbitMQ connection
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct RabbitConfig {
7    /// RabbitMQ connection string (e.g., "amqp://localhost:5672")
8    pub connection_string: String,
9
10    /// Virtual host (default: "/")
11    pub virtual_host: Option<String>,
12
13    /// Connection timeout
14    pub connection_timeout: Option<Duration>,
15
16    /// Heartbeat interval
17    pub heartbeat: Option<Duration>,
18
19    /// Retry configuration for connections
20    pub retry_config: RetryConfig,
21
22    /// Health check configuration
23    pub health_check: HealthCheckConfig,
24
25    /// Connection pool configuration
26    pub pool_config: PoolConfig,
27}
28
29impl RabbitConfig {
30    /// Create a new configuration builder
31    pub fn builder() -> RabbitConfigBuilder {
32        RabbitConfigBuilder::new()
33    }
34}
35
36/// Builder for RabbitConfig
37#[derive(Debug, Clone)]
38pub struct RabbitConfigBuilder {
39    connection_string: String,
40    virtual_host: Option<String>,
41    connection_timeout: Option<Duration>,
42    heartbeat: Option<Duration>,
43    retry_config: RetryConfig,
44    health_check: HealthCheckConfig,
45    pool_config: PoolConfig,
46}
47
48impl RabbitConfigBuilder {
49    /// Create a new builder with default values
50    pub fn new() -> Self {
51        Self {
52            connection_string: "amqp://localhost:5672".to_string(),
53            virtual_host: Some("/".to_string()),
54            connection_timeout: Some(Duration::from_secs(30)),
55            heartbeat: Some(Duration::from_secs(60)),
56            retry_config: RetryConfig::default(),
57            health_check: HealthCheckConfig::default(),
58            pool_config: PoolConfig::default(),
59        }
60    }
61
62    /// Set the connection string
63    pub fn connection_string<S: Into<String>>(mut self, connection_string: S) -> Self {
64        self.connection_string = connection_string.into();
65        self
66    }
67
68    /// Set the virtual host
69    pub fn virtual_host<S: Into<String>>(mut self, virtual_host: S) -> Self {
70        self.virtual_host = Some(virtual_host.into());
71        self
72    }
73
74    /// Clear the virtual host (use default)
75    pub fn no_virtual_host(mut self) -> Self {
76        self.virtual_host = None;
77        self
78    }
79
80    /// Set the connection timeout
81    pub fn connection_timeout(mut self, timeout: Duration) -> Self {
82        self.connection_timeout = Some(timeout);
83        self
84    }
85
86    /// Disable connection timeout
87    pub fn no_connection_timeout(mut self) -> Self {
88        self.connection_timeout = None;
89        self
90    }
91
92    /// Set the heartbeat interval
93    pub fn heartbeat(mut self, heartbeat: Duration) -> Self {
94        self.heartbeat = Some(heartbeat);
95        self
96    }
97
98    /// Disable heartbeat
99    pub fn no_heartbeat(mut self) -> Self {
100        self.heartbeat = None;
101        self
102    }
103
104    /// Set retry configuration
105    pub fn retry_config(mut self, retry_config: RetryConfig) -> Self {
106        self.retry_config = retry_config;
107        self
108    }
109
110    /// Configure retry settings with a builder
111    pub fn retry<F>(mut self, f: F) -> Self
112    where
113        F: FnOnce(RetryConfigBuilder) -> RetryConfigBuilder,
114    {
115        self.retry_config = f(RetryConfigBuilder::new()).build();
116        self
117    }
118
119    /// Set health check configuration
120    pub fn health_check(mut self, health_check: HealthCheckConfig) -> Self {
121        self.health_check = health_check;
122        self
123    }
124
125    /// Configure health check settings with a builder
126    pub fn health<F>(mut self, f: F) -> Self
127    where
128        F: FnOnce(HealthCheckConfigBuilder) -> HealthCheckConfigBuilder,
129    {
130        self.health_check = f(HealthCheckConfigBuilder::new()).build();
131        self
132    }
133
134    /// Set pool configuration
135    pub fn pool_config(mut self, pool_config: PoolConfig) -> Self {
136        self.pool_config = pool_config;
137        self
138    }
139
140    /// Configure pool settings with a builder
141    pub fn pool<F>(mut self, f: F) -> Self
142    where
143        F: FnOnce(PoolConfigBuilder) -> PoolConfigBuilder,
144    {
145        self.pool_config = f(PoolConfigBuilder::new()).build();
146        self
147    }
148
149    /// Build the final configuration
150    pub fn build(self) -> RabbitConfig {
151        RabbitConfig {
152            connection_string: self.connection_string,
153            virtual_host: self.virtual_host,
154            connection_timeout: self.connection_timeout,
155            heartbeat: self.heartbeat,
156            retry_config: self.retry_config,
157            health_check: self.health_check,
158            pool_config: self.pool_config,
159        }
160    }
161}
162
163impl Default for RabbitConfigBuilder {
164    fn default() -> Self {
165        Self::new()
166    }
167}
168
169impl Default for RabbitConfig {
170    fn default() -> Self {
171        Self {
172            connection_string: "amqp://localhost:5672".to_string(),
173            virtual_host: Some("/".to_string()),
174            connection_timeout: Some(Duration::from_secs(30)),
175            heartbeat: Some(Duration::from_secs(60)),
176            retry_config: RetryConfig::default(),
177            health_check: HealthCheckConfig::default(),
178            pool_config: PoolConfig::default(),
179        }
180    }
181}
182
183/// Retry configuration for various operations
184#[derive(Debug, Clone, Serialize, Deserialize)]
185pub struct RetryConfig {
186    /// Maximum number of retry attempts
187    pub max_retries: u32,
188
189    /// Initial delay between retries
190    pub initial_delay: Duration,
191
192    /// Maximum delay between retries
193    pub max_delay: Duration,
194
195    /// Multiplier for exponential backoff
196    pub backoff_multiplier: f64,
197
198    /// Jitter factor (0.0 to 1.0) to add randomness to delays
199    pub jitter: f64,
200}
201
202impl RetryConfig {
203    /// Create a new retry configuration builder
204    pub fn builder() -> RetryConfigBuilder {
205        RetryConfigBuilder::new()
206    }
207}
208
209/// Builder for RetryConfig
210#[derive(Debug, Clone)]
211pub struct RetryConfigBuilder {
212    max_retries: u32,
213    initial_delay: Duration,
214    max_delay: Duration,
215    backoff_multiplier: f64,
216    jitter: f64,
217}
218
219impl RetryConfigBuilder {
220    /// Create a new builder with default values
221    pub fn new() -> Self {
222        Self {
223            max_retries: 3,
224            initial_delay: Duration::from_millis(1000),
225            max_delay: Duration::from_secs(60),
226            backoff_multiplier: 2.0,
227            jitter: 0.1,
228        }
229    }
230
231    /// Set maximum number of retry attempts
232    pub fn max_retries(mut self, max_retries: u32) -> Self {
233        self.max_retries = max_retries;
234        self
235    }
236
237    /// Set initial delay between retries
238    pub fn initial_delay(mut self, delay: Duration) -> Self {
239        self.initial_delay = delay;
240        self
241    }
242
243    /// Set maximum delay between retries
244    pub fn max_delay(mut self, delay: Duration) -> Self {
245        self.max_delay = delay;
246        self
247    }
248
249    /// Set backoff multiplier for exponential backoff
250    pub fn backoff_multiplier(mut self, multiplier: f64) -> Self {
251        self.backoff_multiplier = multiplier;
252        self
253    }
254
255    /// Set jitter factor (0.0 to 1.0)
256    pub fn jitter(mut self, jitter: f64) -> Self {
257        self.jitter = jitter.clamp(0.0, 1.0);
258        self
259    }
260
261    /// Disable jitter
262    pub fn no_jitter(mut self) -> Self {
263        self.jitter = 0.0;
264        self
265    }
266
267    /// Configure for aggressive retries (more attempts, shorter delays)
268    pub fn aggressive(mut self) -> Self {
269        self.max_retries = 5;
270        self.initial_delay = Duration::from_millis(500);
271        self.max_delay = Duration::from_secs(30);
272        self.backoff_multiplier = 1.5;
273        self.jitter = 0.05;
274        self
275    }
276
277    /// Configure for conservative retries (fewer attempts, longer delays)
278    pub fn conservative(mut self) -> Self {
279        self.max_retries = 2;
280        self.initial_delay = Duration::from_secs(2);
281        self.max_delay = Duration::from_secs(120);
282        self.backoff_multiplier = 3.0;
283        self.jitter = 0.2;
284        self
285    }
286
287    /// Build the final configuration
288    pub fn build(self) -> RetryConfig {
289        RetryConfig {
290            max_retries: self.max_retries,
291            initial_delay: self.initial_delay,
292            max_delay: self.max_delay,
293            backoff_multiplier: self.backoff_multiplier,
294            jitter: self.jitter,
295        }
296    }
297}
298
299impl Default for RetryConfigBuilder {
300    fn default() -> Self {
301        Self::new()
302    }
303}
304
305impl Default for RetryConfig {
306    fn default() -> Self {
307        Self {
308            max_retries: 3,
309            initial_delay: Duration::from_millis(1000),
310            max_delay: Duration::from_secs(60),
311            backoff_multiplier: 2.0,
312            jitter: 0.1,
313        }
314    }
315}
316
317/// Health check configuration
318#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct HealthCheckConfig {
320    /// Interval between health checks
321    pub check_interval: Duration,
322
323    /// Timeout for each health check
324    pub check_timeout: Duration,
325
326    /// Enable health monitoring
327    pub enabled: bool,
328}
329
330impl HealthCheckConfig {
331    /// Create a new health check configuration builder
332    pub fn builder() -> HealthCheckConfigBuilder {
333        HealthCheckConfigBuilder::new()
334    }
335}
336
337/// Builder for HealthCheckConfig
338#[derive(Debug, Clone)]
339pub struct HealthCheckConfigBuilder {
340    check_interval: Duration,
341    check_timeout: Duration,
342    enabled: bool,
343}
344
345impl HealthCheckConfigBuilder {
346    /// Create a new builder with default values
347    pub fn new() -> Self {
348        Self {
349            check_interval: Duration::from_secs(30),
350            check_timeout: Duration::from_secs(5),
351            enabled: true,
352        }
353    }
354
355    /// Set health check interval
356    pub fn check_interval(mut self, interval: Duration) -> Self {
357        self.check_interval = interval;
358        self
359    }
360
361    /// Set health check timeout
362    pub fn check_timeout(mut self, timeout: Duration) -> Self {
363        self.check_timeout = timeout;
364        self
365    }
366
367    /// Enable health monitoring
368    pub fn enabled(mut self) -> Self {
369        self.enabled = true;
370        self
371    }
372
373    /// Disable health monitoring
374    pub fn disabled(mut self) -> Self {
375        self.enabled = false;
376        self
377    }
378
379    /// Configure for frequent health checks
380    pub fn frequent(mut self) -> Self {
381        self.check_interval = Duration::from_secs(10);
382        self.check_timeout = Duration::from_secs(3);
383        self.enabled = true;
384        self
385    }
386
387    /// Configure for infrequent health checks
388    pub fn infrequent(mut self) -> Self {
389        self.check_interval = Duration::from_secs(120);
390        self.check_timeout = Duration::from_secs(10);
391        self.enabled = true;
392        self
393    }
394
395    /// Build the final configuration
396    pub fn build(self) -> HealthCheckConfig {
397        HealthCheckConfig {
398            check_interval: self.check_interval,
399            check_timeout: self.check_timeout,
400            enabled: self.enabled,
401        }
402    }
403}
404
405impl Default for HealthCheckConfigBuilder {
406    fn default() -> Self {
407        Self::new()
408    }
409}
410
411impl Default for HealthCheckConfig {
412    fn default() -> Self {
413        Self {
414            check_interval: Duration::from_secs(30),
415            check_timeout: Duration::from_secs(5),
416            enabled: true,
417        }
418    }
419}
420
421/// Connection pool configuration
422#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct PoolConfig {
424    /// Maximum number of connections in the pool
425    pub max_connections: usize,
426
427    /// Minimum number of connections to maintain
428    pub min_connections: usize,
429
430    /// Connection idle timeout
431    pub idle_timeout: Duration,
432}
433
434impl PoolConfig {
435    /// Create a new pool configuration builder
436    pub fn builder() -> PoolConfigBuilder {
437        PoolConfigBuilder::new()
438    }
439}
440
441/// Builder for PoolConfig
442#[derive(Debug, Clone)]
443pub struct PoolConfigBuilder {
444    max_connections: usize,
445    min_connections: usize,
446    idle_timeout: Duration,
447}
448
449impl PoolConfigBuilder {
450    /// Create a new builder with default values
451    pub fn new() -> Self {
452        Self {
453            max_connections: 10,
454            min_connections: 1,
455            idle_timeout: Duration::from_secs(300),
456        }
457    }
458
459    /// Set maximum number of connections
460    pub fn max_connections(mut self, max: usize) -> Self {
461        self.max_connections = max;
462        self
463    }
464
465    /// Set minimum number of connections
466    pub fn min_connections(mut self, min: usize) -> Self {
467        self.min_connections = min;
468        self
469    }
470
471    /// Set connection idle timeout
472    pub fn idle_timeout(mut self, timeout: Duration) -> Self {
473        self.idle_timeout = timeout;
474        self
475    }
476
477    /// Configure for high throughput (more connections)
478    pub fn high_throughput(mut self) -> Self {
479        self.max_connections = 50;
480        self.min_connections = 5;
481        self.idle_timeout = Duration::from_secs(180);
482        self
483    }
484
485    /// Configure for low resource usage (fewer connections)
486    pub fn low_resource(mut self) -> Self {
487        self.max_connections = 3;
488        self.min_connections = 1;
489        self.idle_timeout = Duration::from_secs(600);
490        self
491    }
492
493    /// Configure for single connection mode
494    pub fn single_connection(mut self) -> Self {
495        self.max_connections = 1;
496        self.min_connections = 1;
497        self.idle_timeout = Duration::from_secs(3600);
498        self
499    }
500
501    /// Build the final configuration
502    pub fn build(self) -> PoolConfig {
503        PoolConfig {
504            max_connections: self.max_connections,
505            min_connections: self.min_connections.min(self.max_connections),
506            idle_timeout: self.idle_timeout,
507        }
508    }
509}
510
511impl Default for PoolConfigBuilder {
512    fn default() -> Self {
513        Self::new()
514    }
515}
516
517impl Default for PoolConfig {
518    fn default() -> Self {
519        Self {
520            max_connections: 10,
521            min_connections: 1,
522            idle_timeout: Duration::from_secs(300),
523        }
524    }
525}
526
527#[cfg(test)]
528mod tests {
529    use super::*;
530    use std::time::Duration;
531
532    #[test]
533    fn test_rabbit_config_default() {
534        let config = RabbitConfig::default();
535        assert_eq!(config.connection_string, "amqp://localhost:5672");
536        assert_eq!(config.virtual_host, Some("/".to_string()));
537        assert_eq!(config.connection_timeout, Some(Duration::from_secs(30)));
538        assert_eq!(config.heartbeat, Some(Duration::from_secs(60)));
539    }
540
541    #[test]
542    fn test_retry_config_default() {
543        let config = RetryConfig::default();
544        assert_eq!(config.max_retries, 3);
545        assert_eq!(config.initial_delay, Duration::from_millis(1000));
546        assert_eq!(config.max_delay, Duration::from_secs(60));
547        assert_eq!(config.backoff_multiplier, 2.0);
548        assert_eq!(config.jitter, 0.1);
549    }
550
551    #[test]
552    fn test_health_check_config_presets() {
553        use crate::health::HealthCheckConfigExt;
554
555        let conservative = HealthCheckConfig::conservative();
556        assert_eq!(conservative.check_interval, Duration::from_secs(60));
557        assert_eq!(conservative.check_timeout, Duration::from_secs(10));
558        assert!(conservative.enabled);
559
560        let aggressive = HealthCheckConfig::aggressive();
561        assert_eq!(aggressive.check_interval, Duration::from_secs(10));
562        assert_eq!(aggressive.check_timeout, Duration::from_secs(3));
563        assert!(aggressive.enabled);
564
565        let minimal = HealthCheckConfig::minimal();
566        assert_eq!(minimal.check_interval, Duration::from_secs(300));
567        assert_eq!(minimal.check_timeout, Duration::from_secs(15));
568        assert!(minimal.enabled);
569    }
570
571    #[test]
572    fn test_pool_config_default() {
573        let config = PoolConfig::default();
574        assert_eq!(config.max_connections, 10);
575        assert_eq!(config.min_connections, 1);
576        assert_eq!(config.idle_timeout, Duration::from_secs(300));
577    }
578}