1use crate::{
2 config::QueueConfig,
3 db,
4 error::QueueError,
5 executor::{ProcessedJob, QueueExecutor},
6 types::{QueueJob, QueueJobDetails, QueuePriority, QueueStats},
7 JobHandler, QueueEventEmitter,
8};
9use rusqlite::Connection;
10use std::sync::{Arc, Mutex};
11
12pub struct QueueManager {
31 db: Arc<Mutex<Connection>>,
32 executor: Arc<QueueExecutor>,
33 config: QueueConfig,
34}
35
36impl QueueManager {
37 pub fn new(config: QueueConfig) -> Result<Self, QueueError> {
42 let conn = db::open_database(config.db_path.as_deref())?;
43
44 let requeued = db::requeue_interrupted(&conn)?;
46 if requeued > 0 {
47 tracing::info!(count = requeued, "Requeued interrupted jobs");
48 }
49
50 let db = Arc::new(Mutex::new(conn));
51 let executor = Arc::new(QueueExecutor::new(config.clone(), Arc::clone(&db)));
52
53 Ok(Self {
54 db,
55 executor,
56 config,
57 })
58 }
59
60 pub fn add<H>(&self, job: QueueJob<H>) -> Result<String, QueueError>
62 where
63 H: JobHandler,
64 {
65 let conn = self.db.lock()?;
66 let data = serde_json::to_value(&job.data)?;
67 db::insert_job_full(
68 &conn,
69 &job.id,
70 job.priority.as_i32(),
71 &data,
72 job.trace_id.as_deref(),
73 job.attempt_id.as_ref().map(|a| a.as_str()),
74 job.trial_id.as_ref().map(|t| t.as_str()),
75 )?;
76 Ok(job.id)
77 }
78
79 pub fn cancel(&self, job_id: &str) -> Result<(), QueueError> {
81 let conn = self.db.lock()?;
82 db::cancel_job(&conn, job_id)?;
83 Ok(())
84 }
85
86 pub fn reorder(&self, job_id: &str, new_priority: QueuePriority) -> Result<(), QueueError> {
88 let conn = self.db.lock()?;
89
90 match db::reorder_pending(&conn, job_id, new_priority.as_i32()) {
91 Ok(true) => Ok(()),
92 Ok(false) => {
93 let status = db::get_job(&conn, job_id)
95 .ok()
96 .flatten()
97 .map(|j| j.2)
98 .unwrap_or_else(|| "unknown".to_string());
99 Err(QueueError::Other(format!(
100 "Can only reorder pending jobs (job {} is {})",
101 job_id, status
102 )))
103 }
104 Err(_) => Err(QueueError::NotFound(job_id.to_string())),
105 }
106 }
107
108 pub fn pause(&self) {
110 self.executor.pause();
111 }
112
113 pub fn resume(&self) {
115 self.executor.resume();
116 }
117
118 pub fn is_paused(&self) -> bool {
120 self.executor.is_paused()
121 }
122
123 pub fn list_jobs(&self) -> Result<Vec<(String, String)>, QueueError> {
125 let conn = self.db.lock()?;
126 let jobs = db::list_all_jobs(&conn)?;
127 Ok(jobs
128 .into_iter()
129 .map(|(id, status, _)| (id, status))
130 .collect())
131 }
132
133 pub fn list_jobs_with_data(&self) -> Result<Vec<(String, String, String)>, QueueError> {
135 let conn = self.db.lock()?;
136 Ok(db::list_all_jobs(&conn)?)
137 }
138
139 pub fn get_job_details(&self, job_id: &str) -> Result<Option<QueueJobDetails>, QueueError> {
141 let conn = self.db.lock()?;
142 Ok(db::get_job_details(&conn, job_id)?)
143 }
144
145 pub fn prune(&self, days: u32) -> Result<u32, QueueError> {
148 let conn = self.db.lock()?;
149 Ok(db::prune_old_jobs(&conn, days)?)
150 }
151
152 pub async fn process_one<H>(
159 &self,
160 event_emitter: &Arc<dyn QueueEventEmitter>,
161 ) -> Result<Option<ProcessedJob>, QueueError>
162 where
163 H: JobHandler,
164 {
165 self.executor.process_one::<H>(event_emitter).await
166 }
167
168 pub fn count_by_status(&self) -> Result<QueueStats, QueueError> {
170 let conn = self.db.lock()?;
171 Ok(db::count_by_status(&conn)?)
172 }
173
174 pub fn shutdown(&self) {
179 self.executor.shutdown();
180 }
181
182 pub fn is_shutdown(&self) -> bool {
184 self.executor.is_shutdown()
185 }
186
187 pub fn worker_id(&self) -> &str {
189 &self.config.worker_id
190 }
191
192 pub fn spawn<H>(self, event_emitter: Arc<dyn QueueEventEmitter>) -> Arc<Self>
200 where
201 H: JobHandler + 'static,
202 {
203 let manager = Arc::new(self);
204 let executor = Arc::clone(&manager.executor);
205 executor.spawn::<H>(event_emitter);
206 manager
207 }
208
209 pub fn spawn_on<H>(
214 self,
215 event_emitter: Arc<dyn QueueEventEmitter>,
216 handle: &tokio::runtime::Handle,
217 ) -> Arc<Self>
218 where
219 H: JobHandler + 'static,
220 {
221 let manager = Arc::new(self);
222 let executor = Arc::clone(&manager.executor);
223 executor.spawn_on::<H>(event_emitter, handle);
224 manager
225 }
226}