Skip to main content

vex_queue/
job.rs

1//! Job definitions
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use std::fmt::Debug;
6use uuid::Uuid;
7
8/// Job Identifier
9pub type JobId = Uuid;
10
11/// Job Status
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13pub enum JobStatus {
14    /// Waiting in queue
15    Pending,
16    /// Currently being processed
17    Running,
18    /// Successfully completed
19    Completed,
20    /// Failed (with retry count)
21    Failed(u32),
22    /// Permanently failed after max retries
23    DeadLetter,
24}
25
26/// Generic Job Trait
27#[async_trait::async_trait]
28pub trait Job: Send + Sync + Debug {
29    /// Job name/type
30    fn name(&self) -> &str;
31
32    /// Execute the job
33    async fn execute(&mut self) -> JobResult;
34
35    /// Max retries allowed
36    fn max_retries(&self) -> u32 {
37        3
38    }
39
40    /// Backoff strategy
41    fn backoff_strategy(&self) -> BackoffStrategy {
42        BackoffStrategy::Exponential {
43            initial_secs: 1,
44            multiplier: 2.0,
45        }
46    }
47}
48
49/// Result of job execution
50#[derive(Debug)]
51pub enum JobResult {
52    /// Job succeeded with optional result
53    Success(Option<serde_json::Value>),
54    /// Job failed but should retry
55    Retry(String),
56    /// Job failed permanently
57    Fatal(String),
58}
59
60/// Retry backoff strategy
61#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
62pub enum BackoffStrategy {
63    Constant { secs: u64 },
64    Exponential { initial_secs: u64, multiplier: f64 },
65}
66
67impl BackoffStrategy {
68    pub fn delay(&self, attempt: u32) -> std::time::Duration {
69        match self {
70            Self::Constant { secs } => std::time::Duration::from_secs(*secs),
71            Self::Exponential {
72                initial_secs,
73                multiplier,
74            } => {
75                let secs = (*initial_secs as f64 * multiplier.powi(attempt as i32)) as u64;
76                std::time::Duration::from_secs(secs)
77            }
78        }
79    }
80}
81
82/// A persisted job entry
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct JobEntry {
85    pub id: JobId,
86    pub tenant_id: String,
87    pub job_type: String,
88    pub payload: serde_json::Value,
89    pub status: JobStatus,
90    pub created_at: DateTime<Utc>,
91    pub run_at: DateTime<Utc>,
92    pub attempts: u32,
93    pub last_error: Option<String>,
94    /// The output produced by the job once completed
95    #[serde(default)]
96    pub result: Option<serde_json::Value>,
97}