use crate::app::AppContext;
use crate::error::Result;
use async_trait::async_trait;
#[cfg(feature = "jobs")]
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::fmt::Debug;
use std::time::Duration;
#[async_trait]
#[allow(async_fn_in_trait)] pub trait Job: Send + Sync + Debug {
fn job_type(&self) -> &str;
fn serialize(&self) -> Result<serde_json::Value>;
async fn execute(&self, ctx: &AppContext) -> Result<()>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JobData {
pub job_id: String,
pub job_type: String,
pub payload: serde_json::Value,
pub retry_count: u32,
pub max_retries: u32,
#[cfg(feature = "jobs")]
pub scheduled_at: Option<DateTime<Utc>>,
#[cfg(feature = "jobs")]
pub created_at: DateTime<Utc>,
}
impl JobData {
#[cfg(feature = "jobs")]
pub fn new(
job_id: String,
job_type: String,
payload: serde_json::Value,
max_retries: u32,
) -> Self {
Self {
job_id,
job_type,
payload,
retry_count: 0,
max_retries,
scheduled_at: None,
created_at: Utc::now(),
}
}
#[cfg(feature = "jobs")]
pub fn scheduled(
job_id: String,
job_type: String,
payload: serde_json::Value,
max_retries: u32,
run_at: DateTime<Utc>,
) -> Self {
Self {
job_id,
job_type,
payload,
retry_count: 0,
max_retries,
scheduled_at: Some(run_at),
created_at: Utc::now(),
}
}
pub fn should_retry(&self) -> bool {
self.retry_count < self.max_retries
}
pub fn increment_retry(&mut self) -> u32 {
self.retry_count += 1;
self.retry_count
}
}
#[async_trait]
#[allow(async_fn_in_trait)] pub trait JobQueue: Send + Sync {
async fn enqueue(&self, job: &dyn Job) -> Result<String>;
async fn dequeue(&self) -> Result<Option<JobData>>;
async fn complete(&self, job_id: &str) -> Result<()>;
async fn fail(&self, job_id: &str, error: String) -> Result<()>;
async fn retry(&self, job_id: &str) -> Result<()>;
async fn wait_for_job(&self, timeout: Duration) {
tokio::time::sleep(timeout).await;
}
#[cfg(feature = "jobs")]
async fn schedule(&self, job: &dyn Job, run_at: DateTime<Utc>) -> Result<String>;
fn is_healthy(&self) -> bool;
}