armature_queue/lib.rs
1//! Job queue and background processing for Armature framework.
2//!
3//! Provides a robust job queue system with:
4//! - 📦 Redis-backed persistence
5//! - 🔄 Automatic retries with exponential backoff
6//! - ⭐ Job priorities
7//! - ⏰ Delayed/scheduled jobs
8//! - 💀 Dead letter queue
9//! - 📊 Job progress tracking
10//! - 🎯 Multiple queues
11//! - 👷 Worker pools
12//! - ♻️ Stale-claim reclaim for jobs orphaned by a crashed worker
13//!
14//! ## Delivery semantics
15//!
16//! Delivery is **at-least-once**, so job handlers must be idempotent. A worker
17//! that is SIGKILLed (or whose handler task panics) after its side effects but
18//! before `complete()` is indistinguishable from one that died before them, so
19//! [`Queue::reclaim_stale`] returns the job to its pending queue and it runs
20//! again. [`Worker::start`] runs that reaper in the background on
21//! [`WorkerConfig::visibility_timeout`]; without it such a job would sit in the
22//! `processing` set forever, never retried and never dead-lettered.
23//!
24//! ## Quick Start - Job Creation
25//!
26//! ```
27//! use armature_queue::{Job, JobData, JobPriority};
28//! use serde_json::json;
29//!
30//! let job = Job::new(
31//! "emails",
32//! "send_welcome",
33//! json!({"to": "user@example.com"})
34//! );
35//!
36//! assert_eq!(job.queue, "emails");
37//! assert_eq!(job.job_type, "send_welcome");
38//! assert_eq!(job.priority, JobPriority::Normal);
39//! ```
40//!
41//! ## Job Priorities
42//!
43//! ```
44//! use armature_queue::{Job, JobData, JobPriority};
45//! use serde_json::json;
46//!
47//! // Create high priority job
48//! let urgent = Job::new(
49//! "tasks",
50//! "urgent_task",
51//! json!({})
52//! ).with_priority(JobPriority::High);
53//!
54//! // Create low priority job
55//! let background = Job::new(
56//! "tasks",
57//! "cleanup",
58//! json!({})
59//! ).with_priority(JobPriority::Low);
60//!
61//! assert_eq!(urgent.priority, JobPriority::High);
62//! assert_eq!(background.priority, JobPriority::Low);
63//! assert!(urgent.priority > background.priority);
64//! ```
65//!
66//! ## Delayed Jobs
67//!
68//! ```
69//! use armature_queue::Job;
70//! use serde_json::json;
71//! use chrono::Duration;
72//!
73//! // Schedule job to run in 1 hour
74//! let scheduled = Job::new(
75//! "emails",
76//! "reminder",
77//! json!({"message": "Don't forget!"})
78//! ).schedule_after(Duration::hours(1));
79//!
80//! assert!(scheduled.scheduled_at.is_some());
81//! ```
82//!
83//! ## Queue Configuration
84//!
85//! ```
86//! use armature_queue::QueueConfig;
87//! use std::time::Duration;
88//!
89//! let config = QueueConfig::new("redis://localhost:6379", "emails")
90//! .with_key_prefix("myapp:queue:emails")
91//! .with_max_size(10000)
92//! .with_retention_time(Duration::from_secs(86400));
93//!
94//! assert_eq!(config.queue_name, "emails");
95//! assert_eq!(config.max_size, 10000);
96//! assert_eq!(config.retention_time, Duration::from_secs(86400));
97//! ```
98//!
99//! ## Complete Example
100//!
101//! ```no_run
102//! use armature_queue::*;
103//!
104//! #[tokio::main]
105//! async fn main() -> Result<(), QueueError> {
106//! // Create a queue
107//! let queue = Queue::new("redis://localhost:6379", "default").await?;
108//!
109//! // Enqueue a job
110//! let job_id = queue.enqueue(
111//! "send_email",
112//! serde_json::json!({
113//! "to": "user@example.com",
114//! "subject": "Hello"
115//! })
116//! ).await?;
117//!
118//! // Process jobs
119//! let mut worker = Worker::new(queue);
120//! worker
121//! .register_handler("send_email", |job| async move {
122//! // Send email logic
123//! Ok(())
124//! })
125//! .await;
126//!
127//! worker.start().await?;
128//!
129//! Ok(())
130//! }
131//! ```
132
133pub mod error;
134pub mod job;
135pub mod queue;
136pub mod worker;
137
138pub use error::{QueueError, QueueResult};
139pub use job::{Job, JobData, JobId, JobPriority, JobState, JobStatus};
140pub use queue::{Queue, QueueConfig};
141pub use worker::{JobHandler, Worker, WorkerConfig};
142
143/// Re-export commonly used types
144pub mod prelude {
145 pub use crate::error::{QueueError, QueueResult};
146 pub use crate::job::{Job, JobData, JobId, JobPriority, JobState, JobStatus};
147 pub use crate::queue::{Queue, QueueConfig};
148 pub use crate::worker::{JobHandler, Worker, WorkerConfig};
149}