use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum JobStateKind {
Enqueued,
Processing,
Succeeded,
Failed,
Deleted,
Scheduled,
AwaitingRetry,
}
impl JobStateKind {
pub fn name(&self) -> &'static str {
match self {
JobStateKind::Enqueued => "Enqueued",
JobStateKind::Processing => "Processing",
JobStateKind::Succeeded => "Succeeded",
JobStateKind::Failed => "Failed",
JobStateKind::Deleted => "Deleted",
JobStateKind::Scheduled => "Scheduled",
JobStateKind::AwaitingRetry => "AwaitingRetry",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum JobState {
Enqueued {
enqueued_at: DateTime<Utc>,
queue: String,
},
Processing {
started_at: DateTime<Utc>,
worker_id: String,
server_name: String,
},
Succeeded {
succeeded_at: DateTime<Utc>,
total_duration: u64,
result: Option<String>,
},
Failed {
failed_at: DateTime<Utc>,
exception: String,
stack_trace: Option<String>,
},
Deleted {
deleted_at: DateTime<Utc>,
reason: Option<String>,
},
Scheduled {
scheduled_at: DateTime<Utc>,
enqueue_at: DateTime<Utc>,
reason: String,
},
AwaitingRetry {
scheduled_at: DateTime<Utc>,
retry_at: DateTime<Utc>,
last_exception: String,
},
}
impl JobState {
pub fn kind(&self) -> JobStateKind {
match self {
JobState::Enqueued { .. } => JobStateKind::Enqueued,
JobState::Processing { .. } => JobStateKind::Processing,
JobState::Succeeded { .. } => JobStateKind::Succeeded,
JobState::Failed { .. } => JobStateKind::Failed,
JobState::Deleted { .. } => JobStateKind::Deleted,
JobState::Scheduled { .. } => JobStateKind::Scheduled,
JobState::AwaitingRetry { .. } => JobStateKind::AwaitingRetry,
}
}
pub fn name(&self) -> &'static str {
self.kind().name()
}
pub fn is_final(&self) -> bool {
matches!(
self,
JobState::Succeeded { .. } | JobState::Failed { .. } | JobState::Deleted { .. }
)
}
pub fn is_active(&self) -> bool {
matches!(
self,
JobState::Enqueued { .. }
| JobState::Processing { .. }
| JobState::Scheduled { .. }
| JobState::AwaitingRetry { .. }
)
}
pub fn can_transition_to(&self, target: &JobState) -> bool {
use JobState::*;
match (self, target) {
(Enqueued { .. }, Processing { .. }) => true,
(Enqueued { .. }, Deleted { .. }) => true,
(Enqueued { .. }, Scheduled { .. }) => true,
(Enqueued { .. }, Failed { .. }) => true,
(Processing { .. }, Succeeded { .. }) => true,
(Processing { .. }, Failed { .. }) => true,
(Processing { .. }, Deleted { .. }) => true,
(Processing { .. }, AwaitingRetry { .. }) => true,
(Scheduled { .. }, Enqueued { .. }) => true,
(Scheduled { .. }, Deleted { .. }) => true,
(Failed { .. }, AwaitingRetry { .. }) => true,
(Failed { .. }, Deleted { .. }) => true,
(Failed { .. }, Enqueued { .. }) => true,
(AwaitingRetry { .. }, Enqueued { .. }) => true,
(AwaitingRetry { .. }, Deleted { .. }) => true,
(Succeeded { .. }, Deleted { .. }) => true,
(Deleted { .. }, _) => false,
_ => false,
}
}
pub fn enqueued(queue: impl Into<String>) -> Self {
JobState::Enqueued {
enqueued_at: Utc::now(),
queue: queue.into(),
}
}
pub fn processing(worker_id: impl Into<String>, server_name: impl Into<String>) -> Self {
JobState::Processing {
started_at: Utc::now(),
worker_id: worker_id.into(),
server_name: server_name.into(),
}
}
pub fn succeeded(total_duration: u64, result: Option<String>) -> Self {
JobState::Succeeded {
succeeded_at: Utc::now(),
total_duration,
result,
}
}
pub fn failed(exception: impl Into<String>, stack_trace: Option<String>) -> Self {
JobState::Failed {
failed_at: Utc::now(),
exception: exception.into(),
stack_trace,
}
}
pub fn deleted(reason: Option<String>) -> Self {
JobState::Deleted {
deleted_at: Utc::now(),
reason,
}
}
pub fn scheduled(enqueue_at: DateTime<Utc>, reason: impl Into<String>) -> Self {
JobState::Scheduled {
scheduled_at: Utc::now(),
enqueue_at,
reason: reason.into(),
}
}
pub fn awaiting_retry(retry_at: DateTime<Utc>, last_exception: impl Into<String>) -> Self {
JobState::AwaitingRetry {
scheduled_at: Utc::now(),
retry_at,
last_exception: last_exception.into(),
}
}
}