1use crate::task::{Task, TaskId, TaskPriority, TaskState};
4use dashmap::DashMap;
5use std::collections::BinaryHeap;
6use std::sync::Arc;
7use tokio::sync::{Notify, RwLock};
8use tracing::{debug, info};
9
10#[derive(Debug, Clone)]
12struct QueueItem {
13 task: Task,
14 priority: TaskPriority,
15 sequence: u64,
16}
17
18impl PartialEq for QueueItem {
19 fn eq(&self, other: &Self) -> bool {
20 self.priority == other.priority && self.sequence == other.sequence
21 }
22}
23
24impl Eq for QueueItem {}
25
26impl PartialOrd for QueueItem {
27 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
28 Some(self.cmp(other))
29 }
30}
31
32impl Ord for QueueItem {
33 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
34 match self.priority.cmp(&other.priority) {
36 std::cmp::Ordering::Equal => {
37 other.sequence.cmp(&self.sequence)
39 }
40 ordering => ordering,
41 }
42 }
43}
44
45pub struct TaskQueue {
47 pending: Arc<RwLock<BinaryHeap<QueueItem>>>,
49 tasks: Arc<DashMap<TaskId, Task>>,
51 running: Arc<DashMap<TaskId, Task>>,
53 sequence: Arc<RwLock<u64>>,
55 notify: Arc<Notify>,
57 max_size: usize,
59}
60
61impl TaskQueue {
62 #[must_use]
64 pub fn new() -> Self {
65 Self {
66 pending: Arc::new(RwLock::new(BinaryHeap::new())),
67 tasks: Arc::new(DashMap::new()),
68 running: Arc::new(DashMap::new()),
69 sequence: Arc::new(RwLock::new(0)),
70 notify: Arc::new(Notify::new()),
71 max_size: 0,
72 }
73 }
74
75 #[must_use]
77 pub fn with_max_size(max_size: usize) -> Self {
78 Self {
79 pending: Arc::new(RwLock::new(BinaryHeap::new())),
80 tasks: Arc::new(DashMap::new()),
81 running: Arc::new(DashMap::new()),
82 sequence: Arc::new(RwLock::new(0)),
83 notify: Arc::new(Notify::new()),
84 max_size,
85 }
86 }
87
88 pub async fn enqueue(&self, mut task: Task) -> crate::error::Result<()> {
90 if self.max_size > 0 && self.len().await >= self.max_size {
92 return Err(crate::error::WorkflowError::ResourceLimitExceeded {
93 resource: "queue_size".to_string(),
94 limit: self.max_size.to_string(),
95 });
96 }
97
98 task.set_state(TaskState::Queued)?;
99
100 let priority = task.priority;
101 let task_id = task.id;
102
103 let mut seq = self.sequence.write().await;
105 let sequence = *seq;
106 *seq += 1;
107 drop(seq);
108
109 self.tasks.insert(task_id, task.clone());
111
112 let item = QueueItem {
114 task,
115 priority,
116 sequence,
117 };
118
119 self.pending.write().await.push(item);
120
121 debug!("Enqueued task {} with priority {:?}", task_id, priority);
122
123 self.notify.notify_one();
125
126 Ok(())
127 }
128
129 pub async fn dequeue(&self) -> Option<Task> {
131 loop {
132 let mut pending = self.pending.write().await;
134 if let Some(item) = pending.pop() {
135 drop(pending);
136
137 let mut task = item.task;
138 let task_id = task.id;
139
140 if task.set_state(TaskState::Running).is_ok() {
142 self.running.insert(task_id, task.clone());
143 debug!("Dequeued task {}", task_id);
144 return Some(task);
145 }
146
147 continue;
149 }
150
151 drop(pending);
152
153 self.notify.notified().await;
155 }
156 }
157
158 pub async fn try_dequeue(&self) -> Option<Task> {
160 let mut pending = self.pending.write().await;
161 while let Some(item) = pending.pop() {
162 let mut task = item.task;
163 let task_id = task.id;
164
165 if task.set_state(TaskState::Running).is_ok() {
166 self.running.insert(task_id, task.clone());
167 debug!("Dequeued task {}", task_id);
168 return Some(task);
169 }
170 }
171
172 None
173 }
174
175 pub async fn complete(&self, task_id: TaskId, success: bool) {
177 if let Some((_, mut task)) = self.running.remove(&task_id) {
178 let new_state = if success {
179 TaskState::Completed
180 } else {
181 TaskState::Failed
182 };
183
184 if task.set_state(new_state).is_ok() {
185 self.tasks.insert(task_id, task);
186 }
187
188 info!("Task {} completed with success={}", task_id, success);
189 }
190 }
191
192 #[must_use]
194 pub fn get_task(&self, task_id: &TaskId) -> Option<Task> {
195 self.tasks.get(task_id).map(|t| t.clone())
196 }
197
198 #[must_use]
200 pub fn get_running_task(&self, task_id: &TaskId) -> Option<Task> {
201 self.running.get(task_id).map(|t| t.clone())
202 }
203
204 pub async fn len(&self) -> usize {
206 let pending_count = self.pending.read().await.len();
207 let running_count = self.running.len();
208 pending_count + running_count
209 }
210
211 pub async fn is_empty(&self) -> bool {
213 self.len().await == 0
214 }
215
216 pub async fn pending_count(&self) -> usize {
218 self.pending.read().await.len()
219 }
220
221 #[must_use]
223 pub fn running_count(&self) -> usize {
224 self.running.len()
225 }
226
227 pub async fn clear(&self) {
229 self.pending.write().await.clear();
230 self.running.clear();
231 self.tasks.clear();
232 *self.sequence.write().await = 0;
233 info!("Queue cleared");
234 }
235
236 pub async fn get_pending_tasks(&self) -> Vec<Task> {
238 self.pending
239 .read()
240 .await
241 .iter()
242 .map(|item| item.task.clone())
243 .collect()
244 }
245
246 #[must_use]
248 pub fn get_running_tasks(&self) -> Vec<Task> {
249 self.running
250 .iter()
251 .map(|entry| entry.value().clone())
252 .collect()
253 }
254
255 pub async fn remove(&self, task_id: TaskId) -> bool {
257 if self.running.contains_key(&task_id) {
258 return false;
259 }
260
261 self.tasks.remove(&task_id);
262
263 let mut pending = self.pending.write().await;
265 let items: Vec<_> = pending
266 .drain()
267 .filter(|item| item.task.id != task_id)
268 .collect();
269
270 *pending = items.into_iter().collect();
271
272 true
273 }
274
275 pub async fn requeue(&self, mut task: Task) -> crate::error::Result<()> {
277 self.running.remove(&task.id);
279
280 task.increment_retry();
282
283 if !task.should_retry() {
285 task.set_state(TaskState::Failed)?;
286 self.tasks.insert(task.id, task);
287 return Ok(());
288 }
289
290 task.set_state(TaskState::Retrying)?;
292 let delay = task.retry_delay();
293
294 debug!(
295 "Requeueing task {} after {:?} (attempt {})",
296 task.id,
297 delay,
298 task.retry_count + 1
299 );
300
301 let _task_id = task.id;
302 let queue = self.clone();
303
304 tokio::spawn(async move {
306 tokio::time::sleep(delay).await;
307 let _ = queue.enqueue(task).await;
308 });
309
310 Ok(())
311 }
312
313 #[must_use]
315 pub async fn statistics(&self) -> QueueStatistics {
316 let pending = self.pending_count().await;
317 let running = self.running_count();
318 let total = self.tasks.len();
319
320 let pending_tasks = self.get_pending_tasks().await;
322 let mut low = 0;
323 let mut normal = 0;
324 let mut high = 0;
325 let mut critical = 0;
326
327 for task in pending_tasks {
328 match task.priority {
329 TaskPriority::Low => low += 1,
330 TaskPriority::Normal => normal += 1,
331 TaskPriority::High => high += 1,
332 TaskPriority::Critical => critical += 1,
333 }
334 }
335
336 QueueStatistics {
337 total_tasks: total,
338 pending_tasks: pending,
339 running_tasks: running,
340 low_priority: low,
341 normal_priority: normal,
342 high_priority: high,
343 critical_priority: critical,
344 }
345 }
346}
347
348impl Clone for TaskQueue {
349 fn clone(&self) -> Self {
350 Self {
351 pending: self.pending.clone(),
352 tasks: self.tasks.clone(),
353 running: self.running.clone(),
354 sequence: self.sequence.clone(),
355 notify: self.notify.clone(),
356 max_size: self.max_size,
357 }
358 }
359}
360
361impl Default for TaskQueue {
362 fn default() -> Self {
363 Self::new()
364 }
365}
366
367#[derive(Debug, Clone)]
369pub struct QueueStatistics {
370 pub total_tasks: usize,
372 pub pending_tasks: usize,
374 pub running_tasks: usize,
376 pub low_priority: usize,
378 pub normal_priority: usize,
380 pub high_priority: usize,
382 pub critical_priority: usize,
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389 use std::time::Duration;
390
391 fn create_test_task(name: &str, priority: TaskPriority) -> Task {
392 Task::new(
393 name,
394 crate::task::TaskType::Wait {
395 duration: Duration::from_secs(1),
396 },
397 )
398 .with_priority(priority)
399 }
400
401 #[tokio::test]
402 async fn test_queue_creation() {
403 let queue = TaskQueue::new();
404 assert_eq!(queue.pending_count().await, 0);
405 assert_eq!(queue.running_count(), 0);
406 }
407
408 #[tokio::test]
409 async fn test_enqueue_dequeue() {
410 let queue = TaskQueue::new();
411 let task = create_test_task("task1", TaskPriority::Normal);
412 let task_id = task.id;
413
414 queue.enqueue(task).await.expect("should succeed in test");
415 assert_eq!(queue.pending_count().await, 1);
416
417 let dequeued = queue.try_dequeue().await;
418 assert!(dequeued.is_some());
419 assert_eq!(dequeued.expect("should succeed in test").id, task_id);
420 assert_eq!(queue.running_count(), 1);
421 }
422
423 #[tokio::test]
424 async fn test_priority_ordering() {
425 let queue = TaskQueue::new();
426
427 let task_low = create_test_task("low", TaskPriority::Low);
428 let task_high = create_test_task("high", TaskPriority::High);
429 let task_normal = create_test_task("normal", TaskPriority::Normal);
430
431 queue
432 .enqueue(task_low)
433 .await
434 .expect("should succeed in test");
435 queue
436 .enqueue(task_high.clone())
437 .await
438 .expect("should succeed in test");
439 queue
440 .enqueue(task_normal)
441 .await
442 .expect("should succeed in test");
443
444 let dequeued = queue.try_dequeue().await.expect("should succeed in test");
445 assert_eq!(dequeued.id, task_high.id);
446 }
447
448 #[tokio::test]
449 async fn test_fifo_within_priority() {
450 let queue = TaskQueue::new();
451
452 let task1 = create_test_task("task1", TaskPriority::Normal);
453 let task2 = create_test_task("task2", TaskPriority::Normal);
454 let task3 = create_test_task("task3", TaskPriority::Normal);
455
456 let id1 = task1.id;
457
458 queue.enqueue(task1).await.expect("should succeed in test");
459 queue.enqueue(task2).await.expect("should succeed in test");
460 queue.enqueue(task3).await.expect("should succeed in test");
461
462 let dequeued = queue.try_dequeue().await.expect("should succeed in test");
463 assert_eq!(dequeued.id, id1);
464 }
465
466 #[tokio::test]
467 async fn test_complete_task() {
468 let queue = TaskQueue::new();
469 let task = create_test_task("task1", TaskPriority::Normal);
470 let task_id = task.id;
471
472 queue.enqueue(task).await.expect("should succeed in test");
473 queue.try_dequeue().await;
474
475 assert_eq!(queue.running_count(), 1);
476
477 queue.complete(task_id, true).await;
478 assert_eq!(queue.running_count(), 0);
479
480 let completed_task = queue.get_task(&task_id).expect("should succeed in test");
481 assert_eq!(completed_task.state, TaskState::Completed);
482 }
483
484 #[tokio::test]
485 async fn test_queue_max_size() {
486 let queue = TaskQueue::with_max_size(2);
487
488 let task1 = create_test_task("task1", TaskPriority::Normal);
489 let task2 = create_test_task("task2", TaskPriority::Normal);
490 let task3 = create_test_task("task3", TaskPriority::Normal);
491
492 assert!(queue.enqueue(task1).await.is_ok());
493 assert!(queue.enqueue(task2).await.is_ok());
494 assert!(queue.enqueue(task3).await.is_err());
495 }
496
497 #[tokio::test]
498 async fn test_remove_task() {
499 let queue = TaskQueue::new();
500 let task = create_test_task("task1", TaskPriority::Normal);
501 let task_id = task.id;
502
503 queue.enqueue(task).await.expect("should succeed in test");
504 assert_eq!(queue.pending_count().await, 1);
505
506 let removed = queue.remove(task_id).await;
507 assert!(removed);
508 assert_eq!(queue.pending_count().await, 0);
509 }
510
511 #[tokio::test]
512 async fn test_clear_queue() {
513 let queue = TaskQueue::new();
514
515 queue
516 .enqueue(create_test_task("task1", TaskPriority::Normal))
517 .await
518 .expect("should succeed in test");
519 queue
520 .enqueue(create_test_task("task2", TaskPriority::Normal))
521 .await
522 .expect("should succeed in test");
523
524 queue.clear().await;
525 assert_eq!(queue.pending_count().await, 0);
526 }
527
528 #[tokio::test]
529 async fn test_queue_statistics() {
530 let queue = TaskQueue::new();
531
532 queue
533 .enqueue(create_test_task("low", TaskPriority::Low))
534 .await
535 .expect("should succeed in test");
536 queue
537 .enqueue(create_test_task("normal", TaskPriority::Normal))
538 .await
539 .expect("should succeed in test");
540 queue
541 .enqueue(create_test_task("high", TaskPriority::High))
542 .await
543 .expect("should succeed in test");
544
545 let stats = queue.statistics().await;
546 assert_eq!(stats.pending_tasks, 3);
547 assert_eq!(stats.low_priority, 1);
548 assert_eq!(stats.normal_priority, 1);
549 assert_eq!(stats.high_priority, 1);
550 }
551
552 #[tokio::test]
553 async fn test_requeue() {
554 let queue = TaskQueue::new();
555 let mut task = create_test_task("task1", TaskPriority::Normal);
556 task.retry = crate::task::RetryPolicy {
557 max_attempts: 3,
558 initial_delay: Duration::from_millis(10),
559 max_delay: Duration::from_secs(1),
560 backoff_multiplier: 2.0,
561 exponential_backoff: true,
562 };
563
564 let _task_id = task.id;
565
566 queue.enqueue(task).await.expect("should succeed in test");
567 let task = queue.try_dequeue().await.expect("should succeed in test");
568
569 queue.requeue(task).await.expect("should succeed in test");
571
572 tokio::time::sleep(Duration::from_millis(500)).await;
576
577 assert!(queue.pending_count().await > 0 || queue.running_count() > 0);
579 }
580}