Skip to main content

simple_queue/
job.rs

1use super::*;
2
3/// Represents a job processed/processing by the queue.
4pub struct Job {
5    /// Job ID
6    pub id: uuid::Uuid,
7    /// Fingerprint, made as a soft key for deduplication purposes or cancelling.
8    /// Does not violate any database constraints.
9    pub fingerprint: Option<String>,
10    /// Unique key - database constraint on `unique_key` jobs in `pending` and `running` states.
11    /// Repeated inserts with the same `unique_key` will be rejected by the database.
12    pub unique_key: Option<String>,
13    /// Name of the queue job belongs to.
14    pub queue: String,
15    /// Payload - `serde_json::Value`,
16    pub job_data: serde_json::Value,
17    /// Current status of the job in string form
18    pub status: String,
19    /// Timestamp when the job was created.
20    pub created_at: chrono::DateTime<chrono::Utc>,
21    /// Timestamp when the job is scheduled to run.
22    pub run_at: Option<chrono::DateTime<chrono::Utc>>,
23    /// Timestamp when the job was last updated (for use by heartbeat)
24    pub updated_at: Option<chrono::DateTime<chrono::Utc>>,
25    /// Timestamp when the job was completed
26    pub completed_at: Option<chrono::DateTime<chrono::Utc>>,
27    /// Attempt count of the job
28    pub attempt: i32,
29    /// Maximum number of attempts for the job
30    pub max_attempts: i32,
31    pub(crate) reprocess_count: i32,
32}
33impl std::fmt::Debug for Job {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        f.debug_struct("Job")
36            .field("id", &self.id)
37            .field("fingerprint", &self.fingerprint)
38            .field("unique_key", &self.unique_key)
39            .field("queue", &self.queue)
40            .field("status", &self.status)
41            .field("created_at", &self.created_at)
42            .field("attempt", &self.attempt)
43            .field("max_attempts", &self.max_attempts)
44            .finish()
45    }
46}
47impl Default for Job {
48    fn default() -> Self {
49        Self {
50            id: uuid::Uuid::new_v4(),
51            fingerprint: None,
52            unique_key: None,
53            queue: "default".into(),
54            job_data: serde_json::Value::default(),
55            status: result::JobResultInternal::Pending.to_string(),
56            created_at: chrono::Utc::now(),
57            run_at: None,
58            updated_at: None,
59            completed_at: None,
60            attempt: 0,
61            max_attempts: 3,
62            reprocess_count: 0,
63        }
64    }
65}
66
67impl Job {
68    /// Create a new [`Job`] instance with the given queue name and job payload.
69    pub fn new<T: serde::Serialize + serde::de::DeserializeOwned>(
70        queue: &'static str,
71        job_data: T,
72    ) -> Self {
73        Self {
74            queue: queue.to_string(),
75            job_data: serde_json::to_value(job_data).unwrap_or_default(),
76            ..Default::default()
77        }
78    }
79    /// Builder method: sets [`Job::unique_key`]
80    pub fn with_unique_key(self, unique_key: impl Into<String>) -> Self {
81        Self {
82            unique_key: Some(unique_key.into()),
83            ..self
84        }
85    }
86    /// Builder method: sets [`Job::run_at`]
87    pub fn with_run_at(self, run_at: chrono::DateTime<chrono::Utc>) -> Self {
88        Self {
89            run_at: Some(run_at),
90            ..self
91        }
92    }
93    /// Builder method: sets [`Job::max_attempts`]
94    pub fn with_max_attempts(self, max_attempts: i32) -> Self {
95        Self {
96            max_attempts,
97            ..self
98        }
99    }
100    /// Builder method: sets [`Job::fingerprint`]
101    pub fn with_fingerprint(self, fingerprint: impl Into<String>) -> Self {
102        Self {
103            fingerprint: Some(fingerprint.into()),
104            ..self
105        }
106    }
107}
108
109pub trait JobExt<T> {
110    fn into_job(self, queue: &'static str) -> Job;
111}
112
113impl<T: serde::Serialize + serde::de::DeserializeOwned> JobExt<T> for T {
114    fn into_job(self, queue: &'static str) -> Job {
115        Job::new(queue, self)
116    }
117}