use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use uuid::Uuid;
pub type JobId = Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum JobStatus {
Pending,
Running,
Completed,
Failed(u32),
DeadLetter,
}
#[async_trait::async_trait]
pub trait Job: Send + Sync + Debug {
fn name(&self) -> &str;
async fn execute(&mut self) -> JobResult;
fn max_retries(&self) -> u32 {
3
}
fn backoff_strategy(&self) -> BackoffStrategy {
BackoffStrategy::Exponential {
initial_secs: 1,
multiplier: 2.0,
}
}
}
#[derive(Debug)]
pub enum JobResult {
Success(Option<serde_json::Value>),
Retry(String),
Fatal(String),
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum BackoffStrategy {
Constant { secs: u64 },
Exponential { initial_secs: u64, multiplier: f64 },
}
impl BackoffStrategy {
pub fn delay(&self, attempt: u32) -> std::time::Duration {
match self {
Self::Constant { secs } => std::time::Duration::from_secs(*secs),
Self::Exponential {
initial_secs,
multiplier,
} => {
let secs = (*initial_secs as f64 * multiplier.powi(attempt as i32)) as u64;
std::time::Duration::from_secs(secs)
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JobEntry {
pub id: JobId,
pub tenant_id: String,
pub job_type: String,
pub payload: serde_json::Value,
pub status: JobStatus,
pub created_at: DateTime<Utc>,
pub run_at: DateTime<Utc>,
pub attempts: u32,
pub last_error: Option<String>,
#[serde(default)]
pub result: Option<serde_json::Value>,
}