use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use uuid::Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub enum QueueOrdering {
#[default]
Fifo,
Fastest,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct QueueConfig {
pub ordering: QueueOrdering,
}
impl Default for QueueConfig {
fn default() -> Self {
Self {
ordering: QueueOrdering::Fifo,
}
}
}
impl QueueConfig {
pub fn new(ordering: QueueOrdering) -> Self {
Self { ordering }
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct JobListItem {
pub id: Uuid,
pub queue: String,
pub job_type: String,
pub status: String,
pub run_at: DateTime<Utc>,
pub priority: i32,
pub max_attempts: i32,
pub last_error_code: Option<String>,
pub last_error_message: Option<String>,
pub dlq_reason_code: Option<String>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Job {
pub dataset_id: String,
pub replay_of_job_id: Option<Uuid>,
pub id: Uuid,
pub queue: String,
pub job_type: String,
#[cfg_attr(feature = "sqlx", sqlx(rename = "payload_json"))]
pub payload: Value,
pub run_at: DateTime<Utc>,
pub status: String,
pub priority: i32,
pub max_attempts: i32,
pub locked_at: Option<DateTime<Utc>>,
pub locked_by: Option<String>,
pub lock_expires_at: Option<DateTime<Utc>>,
pub dlq_reason_code: Option<String>,
pub dlq_at: Option<DateTime<Utc>>,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
impl Job {
pub fn new(job_type: impl Into<String>, payload: Value) -> Self {
let now = Utc::now();
Self {
dataset_id: "default".to_string(),
replay_of_job_id: None,
id: Uuid::new_v4(),
queue: "default".to_string(),
job_type: job_type.into(),
payload,
run_at: now,
status: JobStatus::Queued.as_str().to_string(),
priority: 0,
max_attempts: 25,
locked_at: None,
locked_by: None,
lock_expires_at: None,
dlq_reason_code: None,
dlq_at: None,
created_at: now,
updated_at: now,
}
}
pub fn queue(mut self, queue: impl Into<String>) -> Self {
self.queue = queue.into();
self
}
pub fn priority(mut self, priority: i32) -> Self {
self.priority = priority;
self
}
pub fn max_attempts(mut self, max_attempts: i32) -> Self {
self.max_attempts = max_attempts;
self
}
pub fn run_at(mut self, run_at: DateTime<Utc>) -> Self {
self.run_at = run_at;
self
}
pub fn payload_json(&self) -> &Value {
&self.payload
}
pub fn payload_typed<T: serde::de::DeserializeOwned>(&self) -> Result<T, crate::error::Error> {
serde_json::from_value(self.payload.clone())
.map_err(crate::error::Error::PayloadDeserialization)
}
}
#[async_trait::async_trait]
pub trait JobProcessor: Send + Sync {
async fn process(&self, job: Job) -> anyhow::Result<()>;
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewJob {
pub queue: String,
pub job_type: String,
pub payload_json: Value,
pub run_at: DateTime<Utc>,
pub priority: i32,
pub max_attempts: i32,
}
impl From<Job> for NewJob {
fn from(job: Job) -> Self {
NewJob {
queue: job.queue,
job_type: job.job_type,
payload_json: job.payload,
run_at: job.run_at,
priority: job.priority,
max_attempts: job.max_attempts,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum JobStatus {
Queued,
Running,
Succeeded,
Failed,
Dlq,
Canceled,
}
impl JobStatus {
pub fn as_str(&self) -> &'static str {
match self {
JobStatus::Queued => "queued",
JobStatus::Running => "running",
JobStatus::Succeeded => "succeeded",
JobStatus::Failed => "failed",
JobStatus::Dlq => "dlq",
JobStatus::Canceled => "canceled",
}
}
}
pub type JobHandler = std::sync::Arc<
dyn Fn(Job) -> std::pin::Pin<Box<dyn std::future::Future<Output = anyhow::Result<()>> + Send>>
+ Send
+ Sync,
>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct Event {
pub sequence_no: i64,
pub stream_name: String,
pub event_type: String,
pub payload_json: serde_json::Value,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NewEvent {
pub event_type: String,
pub payload_json: serde_json::Value,
}
impl NewEvent {
pub fn new(event_type: impl Into<String>, payload_json: serde_json::Value) -> Self {
Self {
event_type: event_type.into(),
payload_json,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(feature = "sqlx", derive(sqlx::FromRow))]
pub struct ConsumerGroupStatus {
pub consumer_group: String,
pub stream_name: String,
pub last_acked_seq: i64,
pub updated_at: DateTime<Utc>,
}