elif_queue/
config.rs

1//! Queue configuration types and builders
2
3use std::time::Duration;
4use serde::{Deserialize, Serialize};
5use service_builder::builder;
6
7/// Configuration for queue backends
8#[derive(Debug, Clone, Serialize, Deserialize)]
9#[builder]
10pub struct QueueConfig {
11    /// Maximum number of concurrent workers
12    #[builder(default = "4", getter)]
13    pub max_workers: usize,
14    
15    /// Default job timeout
16    #[builder(default = "Duration::from_secs(300)", getter)]
17    pub default_timeout: Duration,
18    
19    /// Polling interval for checking new jobs
20    #[builder(default = "Duration::from_millis(100)", getter)]
21    pub poll_interval: Duration,
22    
23    /// Maximum queue size (0 = unlimited)
24    #[builder(default = "0", getter)]
25    pub max_queue_size: usize,
26    
27    /// Enable job persistence
28    #[builder(default = "true", getter)]
29    pub enable_persistence: bool,
30    
31    /// Cleanup interval for completed/failed jobs
32    #[builder(default = "Duration::from_secs(3600)")]
33    pub cleanup_interval: Duration,
34    
35    /// How long to keep completed jobs before cleanup
36    #[builder(default = "Duration::from_secs(86400)")]
37    pub completed_job_ttl: Duration,
38    
39    /// How long to keep failed jobs before cleanup
40    #[builder(default = "Duration::from_secs(604800)")]
41    pub failed_job_ttl: Duration,
42}
43
44impl Default for QueueConfig {
45    fn default() -> Self {
46        Self {
47            max_workers: 4,
48            default_timeout: Duration::from_secs(300),
49            poll_interval: Duration::from_millis(100),
50            max_queue_size: 0,
51            enable_persistence: true,
52            cleanup_interval: Duration::from_secs(3600),
53            completed_job_ttl: Duration::from_secs(86400), // 1 day
54            failed_job_ttl: Duration::from_secs(604800),   // 1 week
55        }
56    }
57}
58
59/// Redis-specific configuration
60#[derive(Debug, Clone, Serialize, Deserialize)]
61#[builder]
62pub struct RedisConfig {
63    /// Redis connection URL
64    #[builder(default = "\"redis://localhost:6379\".to_string()", getter)]
65    pub url: String,
66    
67    /// Connection pool size
68    #[builder(default = "10", getter)]
69    pub pool_size: u32,
70    
71    /// Connection timeout
72    #[builder(default = "Duration::from_secs(5)")]
73    pub connect_timeout: Duration,
74    
75    /// Command timeout
76    #[builder(default = "Duration::from_secs(30)")]
77    pub command_timeout: Duration,
78    
79    /// Queue key prefix
80    #[builder(default = "\"elif_queue\".to_string()")]
81    pub key_prefix: String,
82    
83    /// Enable Redis persistence
84    #[builder(default = "true")]
85    pub enable_persistence: bool,
86}
87
88impl Default for RedisConfig {
89    fn default() -> Self {
90        Self {
91            url: "redis://localhost:6379".to_string(),
92            pool_size: 10,
93            connect_timeout: Duration::from_secs(5),
94            command_timeout: Duration::from_secs(30),
95            key_prefix: "elif_queue".to_string(),
96            enable_persistence: true,
97        }
98    }
99}
100
101impl QueueConfigBuilder {
102    /// Create a development configuration with fast polling and small timeouts
103    pub fn development() -> Self {
104        QueueConfigBuilder::new()
105            .max_workers(2)
106            .poll_interval(Duration::from_millis(50))
107            .default_timeout(Duration::from_secs(60))
108            .enable_persistence(false)
109    }
110    
111    /// Create a production configuration with conservative defaults
112    pub fn production() -> Self {
113        QueueConfigBuilder::new()
114            .max_workers(8)
115            .poll_interval(Duration::from_millis(500))
116            .default_timeout(Duration::from_secs(600))
117            .enable_persistence(true)
118            .cleanup_interval(Duration::from_secs(1800)) // 30 minutes
119    }
120    
121    /// Create a testing configuration with minimal overhead
122    pub fn testing() -> Self {
123        QueueConfigBuilder::new()
124            .max_workers(1)
125            .poll_interval(Duration::from_millis(10))
126            .default_timeout(Duration::from_secs(10))
127            .enable_persistence(false)
128            .cleanup_interval(Duration::from_secs(1))
129            .completed_job_ttl(Duration::from_secs(1))
130            .failed_job_ttl(Duration::from_secs(1))
131    }
132}
133
134impl RedisConfigBuilder {
135    /// Create a development Redis configuration
136    pub fn development() -> Self {
137        RedisConfigBuilder::new()
138            .url("redis://localhost:6379".to_string())
139            .pool_size(5)
140            .key_prefix("elif_queue_dev".to_string())
141    }
142    
143    /// Create a production Redis configuration
144    pub fn production() -> Self {
145        RedisConfigBuilder::new()
146            .pool_size(20)
147            .connect_timeout(Duration::from_secs(10))
148            .command_timeout(Duration::from_secs(60))
149            .key_prefix("elif_queue_prod".to_string())
150    }
151    
152    /// Create a testing Redis configuration
153    pub fn testing() -> Self {
154        RedisConfigBuilder::new()
155            .url("redis://localhost:6379".to_string())
156            .pool_size(2)
157            .key_prefix("elif_queue_test".to_string())
158            .enable_persistence(false)
159    }
160}
161
162#[cfg(test)]
163mod tests {
164    use super::*;
165    
166    #[test]
167    fn test_default_queue_config() {
168        let config = QueueConfig::default();
169        assert_eq!(config.max_workers, 4);
170        assert_eq!(config.default_timeout, Duration::from_secs(300));
171        assert_eq!(config.poll_interval, Duration::from_millis(100));
172        assert!(config.enable_persistence);
173    }
174    
175    #[test]
176    fn test_queue_config_builder() {
177        let config = QueueConfigBuilder::new()
178            .max_workers(8)
179            .default_timeout(Duration::from_secs(600))
180            .build().expect("Failed to build config");
181        
182        assert_eq!(*config.get_max_workers(), 8);
183        assert_eq!(*config.get_default_timeout(), Duration::from_secs(600));
184        assert_eq!(*config.get_poll_interval(), Duration::from_millis(100)); // Default
185    }
186    
187    #[test]
188    fn test_development_config() {
189        let config = QueueConfigBuilder::development().build().expect("Failed to build config");
190        assert_eq!(*config.get_max_workers(), 2);
191        assert_eq!(*config.get_poll_interval(), Duration::from_millis(50));
192        assert!(!*config.get_enable_persistence());
193    }
194    
195    #[test]
196    fn test_production_config() {
197        let config = QueueConfigBuilder::production().build().expect("Failed to build config");
198        assert_eq!(*config.get_max_workers(), 8);
199        assert_eq!(*config.get_poll_interval(), Duration::from_millis(500));
200        assert!(*config.get_enable_persistence());
201    }
202    
203    #[test]
204    fn test_redis_config_builder() {
205        let config = RedisConfigBuilder::new()
206            .url("redis://custom:6380".to_string())
207            .pool_size(15)
208            .build().expect("Failed to build config");
209        
210        assert_eq!(config.get_url(), "redis://custom:6380");
211        assert_eq!(*config.get_pool_size(), 15);
212    }
213}