Skip to main content

backyard_core/
job.rs

1use crate::error::Result;
2use async_trait::async_trait;
3use std::sync::Arc;
4
5pub type JobId = uuid::Uuid;
6
7#[derive(Clone)]
8pub struct JobContext {
9    pub queue: Arc<dyn crate::queue::Queue>,
10    pub worker_id: String,
11}
12
13impl JobContext {
14    pub async fn enqueue<J: Job>(&self, job: J, opts: crate::options::JobOptions) -> Result<JobId> {
15        let payload = serde_json::to_vec(&job)?;
16        let scheduled_at = opts.scheduled_at();
17
18        let req = crate::queue::EnqueueRequest {
19            job_type: J::NAME.to_string(),
20            queue: opts.queue,
21            payload,
22            max_retries: opts.max_retries,
23            priority: opts.priority,
24            scheduled_at,
25        };
26
27        self.queue.push(req).await
28    }
29}
30
31/// A background job that can be enqueued and executed by workers.
32///
33/// # Implementing Job
34///
35/// Your job struct must:
36/// 1. Implement `Serialize` and `Deserialize` (for storage)
37/// 2. Implement `Send + Sync` (for Tokio task boundaries)
38/// 3. Provide a `const NAME: &'static str` unique identifier
39/// 4. Implement async `execute(self, ctx) -> Result<()>`
40///
41/// # Example
42///
43/// ```ignore
44/// use backyard_core::{Job, JobContext, Result};
45/// use async_trait::async_trait;
46/// use serde::{Serialize, Deserialize};
47///
48/// #[derive(Serialize, Deserialize)]
49/// struct SendEmail {
50///     to: String,
51///     subject: String,
52/// }
53///
54/// #[async_trait]
55/// impl Job for SendEmail {
56///     const NAME: &'static str = "SendEmail";
57///
58///     async fn execute(self, _ctx: &JobContext) -> Result<()> {
59///         println!("Sending {} to {}", self.subject, self.to);
60///         Ok(())
61///     }
62/// }
63/// ```
64#[async_trait]
65pub trait Job: serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static {
66    /// Unique identifier for this job type.
67    /// Must be stable and unique across your entire application.
68    const NAME: &'static str;
69
70    /// Default enqueue options for this job type.
71    /// Override to customize queue name, retries, priority, etc.
72    fn options() -> crate::options::JobOptions {
73        crate::options::JobOptions::default()
74    }
75
76    /// Execute the job.
77    ///
78    /// # Arguments
79    /// * `ctx` - Job context including the queue (for enqueueing other jobs from within)
80    ///
81    /// # Returns
82    /// * `Ok(())` - Job succeeded
83    /// * `Err(BackyardError)` - Job failed; will be retried or moved to dead letter queue
84    async fn execute(self, ctx: &JobContext) -> Result<()>;
85}
86
87#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
88pub struct RawJob {
89    pub id: JobId,
90    pub job_type: String,
91    pub queue: String,
92    pub payload: Vec<u8>,
93    pub attempts: u32,
94    pub max_retries: u32,
95    pub scheduled_at: chrono::DateTime<chrono::Utc>,
96    pub created_at: chrono::DateTime<chrono::Utc>,
97    pub error: Option<String>,
98}