1use async_trait::async_trait;
2use std::collections::VecDeque;
3use std::sync::Arc;
4use tokio::sync::Mutex;
5use crate::job::{JobWrapper, JobStatus};
6use crate::stats::StatsTracker;
7use crate::Result;
8
9#[async_trait]
11pub trait QueueBackend: Send + Sync {
12 async fn enqueue(&self, job: JobWrapper) -> Result<()>;
14 async fn dequeue(&self) -> Result<Option<JobWrapper>>;
16 async fn complete(&self, job_id: &str) -> Result<()>;
18 async fn fail(&self, job_id: &str, error: String) -> Result<()>;
20 async fn retry(&self, job: JobWrapper) -> Result<()>;
22 async fn move_to_dead_letter(&self, job: JobWrapper) -> Result<()>;
24 async fn list_dead_letter(&self) -> Result<Vec<JobWrapper>>;
26 async fn retry_from_dead_letter(&self, job_id: &str) -> Result<()>;
28 async fn clear(&self) -> Result<()>;
30}
31
32pub struct MemoryBackend {
34 queue: Arc<Mutex<VecDeque<JobWrapper>>>,
35 dead_letter: Arc<Mutex<Vec<JobWrapper>>>,
36}
37
38impl MemoryBackend {
39 pub fn new() -> Self {
41 Self {
42 queue: Arc::new(Mutex::new(VecDeque::new())),
43 dead_letter: Arc::new(Mutex::new(Vec::new())),
44 }
45 }
46}
47
48impl Default for MemoryBackend {
49 fn default() -> Self {
50 Self::new()
51 }
52}
53
54#[async_trait]
55impl QueueBackend for MemoryBackend {
56 async fn enqueue(&self, mut job: JobWrapper) -> Result<()> {
57 job.status = JobStatus::Pending;
58 let mut queue = self.queue.lock().await;
59
60 let pos = queue.iter().position(|j| j.priority < job.priority)
62 .unwrap_or(queue.len());
63 queue.insert(pos, job);
64
65 Ok(())
66 }
67
68 async fn dequeue(&self) -> Result<Option<JobWrapper>> {
69 let mut queue = self.queue.lock().await;
70
71 let now = chrono::Utc::now().timestamp();
73 let pos = queue.iter().position(|j| {
74 j.status == JobStatus::Pending &&
75 j.scheduled_at.map(|t| t <= now).unwrap_or(true)
76 });
77
78 if let Some(pos) = pos {
79 let mut job = queue.remove(pos).unwrap();
80 job.status = JobStatus::Running;
81 job.attempts += 1;
82 Ok(Some(job))
83 } else {
84 Ok(None)
85 }
86 }
87
88 async fn complete(&self, _job_id: &str) -> Result<()> {
89 Ok(())
91 }
92
93 async fn fail(&self, _job_id: &str, _error: String) -> Result<()> {
94 Ok(())
96 }
97
98 async fn retry(&self, job: JobWrapper) -> Result<()> {
99 self.enqueue(job).await
100 }
101
102 async fn move_to_dead_letter(&self, mut job: JobWrapper) -> Result<()> {
103 job.status = JobStatus::DeadLetter;
104 let mut dlq = self.dead_letter.lock().await;
105 dlq.push(job);
106 Ok(())
107 }
108
109 async fn list_dead_letter(&self) -> Result<Vec<JobWrapper>> {
110 let dlq = self.dead_letter.lock().await;
111 Ok(dlq.clone())
112 }
113
114 async fn retry_from_dead_letter(&self, job_id: &str) -> Result<()> {
115 let mut dlq = self.dead_letter.lock().await;
116 if let Some(pos) = dlq.iter().position(|j| j.id == job_id) {
117 let mut job = dlq.remove(pos);
118 job.status = JobStatus::Pending;
119 job.attempts = 0;
120 job.error = None;
121 drop(dlq); self.enqueue(job).await?;
123 }
124 Ok(())
125 }
126
127 async fn clear(&self) -> Result<()> {
128 let mut queue = self.queue.lock().await;
129 queue.clear();
130 Ok(())
131 }
132}
133
134pub struct Queue {
136 backend: Arc<dyn QueueBackend>,
137 stats: StatsTracker,
138}
139
140impl Queue {
141 pub fn new(backend: Arc<dyn QueueBackend>) -> Self {
143 Self {
144 backend,
145 stats: StatsTracker::new(),
146 }
147 }
148
149 pub fn memory() -> Self {
151 Self::new(Arc::new(MemoryBackend::new()))
152 }
153
154 pub async fn enqueue(&self, job: JobWrapper) -> Result<String> {
156 let job_id = job.id.clone();
157 self.backend.enqueue(job).await?;
158 self.stats.increment_enqueued().await;
159 Ok(job_id)
160 }
161
162 pub async fn dequeue(&self) -> Result<Option<JobWrapper>> {
164 let job = self.backend.dequeue().await?;
165 if job.is_some() {
166 self.stats.mark_running().await;
167 }
168 Ok(job)
169 }
170
171 pub async fn complete(&self, job_id: &str) -> Result<()> {
173 self.backend.complete(job_id).await?;
174 self.stats.increment_processed().await;
175 Ok(())
176 }
177
178 pub async fn fail(&self, job_id: &str, error: String) -> Result<()> {
180 self.backend.fail(job_id, error).await?;
181 self.stats.increment_failed().await;
182 Ok(())
183 }
184
185 pub async fn retry(&self, job: JobWrapper) -> Result<()> {
187 self.backend.retry(job).await?;
188 self.stats.increment_retried().await;
189 Ok(())
190 }
191
192 pub async fn move_to_dead_letter(&self, job: JobWrapper) -> Result<()> {
194 self.backend.move_to_dead_letter(job).await?;
195 self.stats.increment_dead_letter().await;
196 Ok(())
197 }
198
199 pub async fn list_dead_letter(&self) -> Result<Vec<JobWrapper>> {
201 self.backend.list_dead_letter().await
202 }
203
204 pub async fn retry_from_dead_letter(&self, job_id: &str) -> Result<()> {
206 self.backend.retry_from_dead_letter(job_id).await
207 }
208
209 pub async fn clear(&self) -> Result<()> {
211 self.backend.clear().await?;
212 self.stats.reset().await;
213 Ok(())
214 }
215
216 pub async fn get_stats(&self) -> crate::stats::QueueStats {
218 self.stats.get_stats().await
219 }
220}
221
222#[cfg(test)]
223mod tests {
224 use super::*;
225 use crate::job::Job;
226 use serde::{Deserialize, Serialize};
227
228 #[derive(Serialize, Deserialize)]
229 struct TestJob {
230 value: i32,
231 }
232
233 #[async_trait::async_trait]
234 impl Job for TestJob {
235 async fn perform(&self) -> crate::Result<()> {
236 Ok(())
237 }
238 }
239
240 #[tokio::test]
241 async fn test_enqueue_dequeue() {
242 let queue = Queue::memory();
243 let job = JobWrapper::new(&TestJob { value: 42 }).unwrap();
244
245 queue.enqueue(job).await.unwrap();
246 let dequeued = queue.dequeue().await.unwrap();
247
248 assert!(dequeued.is_some());
249 }
250}