1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::fmt;
4use std::time::Duration;
5
6pub const MAX_QUEUE_SIZE: usize = 10_000;
7pub const MAX_RETRIES: u32 = 3;
8
9#[derive(Debug, Clone, PartialEq)]
10pub enum TaskResult {
11 Success,
12 RetryableError(String),
13 PermanentError(String),
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub enum TaskOutput {
18 Success(serde_json::Value),
19 RetryableError(String),
20 PermanentError(String),
21}
22
23impl fmt::Display for TaskResult {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 TaskResult::Success => write!(f, "Success"),
27 TaskResult::RetryableError(err) => write!(f, "Retryable Error: {}", err),
28 TaskResult::PermanentError(err) => write!(f, "Permanent Error: {}", err),
29 }
30 }
31}
32
33impl From<TaskOutput> for TaskResult {
34 fn from(output: TaskOutput) -> Self {
35 match output {
36 TaskOutput::Success(_) => TaskResult::Success,
37 TaskOutput::RetryableError(e) => TaskResult::RetryableError(e),
38 TaskOutput::PermanentError(e) => TaskResult::PermanentError(e),
39 }
40 }
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
44pub enum TaskStatus {
45 Queued,
46 InProgress,
47 Completed,
48 Failed,
49 Retrying,
50 Cancelled,
51}
52
53impl fmt::Display for TaskStatus {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 match self {
56 TaskStatus::Queued => write!(f, "queued"),
57 TaskStatus::InProgress => write!(f, "in_progress"),
58 TaskStatus::Completed => write!(f, "completed"),
59 TaskStatus::Failed => write!(f, "failed"),
60 TaskStatus::Retrying => write!(f, "retrying"),
61 TaskStatus::Cancelled => write!(f, "cancelled"),
62 }
63 }
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct TaskState {
68 pub id: String,
69 pub task_name: String,
70 pub task_data: serde_json::Value,
71 pub status: TaskStatus,
72 pub retry_count: u32,
73 pub created_at: DateTime<Utc>,
74 pub started_at: Option<DateTime<Utc>>,
75 pub completed_at: Option<DateTime<Utc>>,
76 pub duration_ms: Option<u64>,
77 pub error_message: Option<String>,
78 pub worker_id: Option<usize>,
79}
80
81impl TaskState {
82 pub fn is_terminal(&self) -> bool {
83 matches!(self.status, TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled)
84 }
85
86 pub fn can_retry(&self) -> bool {
87 self.retry_count < MAX_RETRIES
88 && matches!(self.status, TaskStatus::Failed)
89 && self
90 .error_message
91 .as_ref()
92 .is_some_and(|msg| !msg.contains("permanent"))
93 }
94
95 pub fn age(&self) -> chrono::Duration {
96 Utc::now().signed_duration_since(self.created_at)
97 }
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct JobMetrics {
102 pub status: TaskStatus,
103 pub created_at: DateTime<Utc>,
104 pub started_at: Option<DateTime<Utc>>,
105 pub retry_count: u32,
106 pub error_message: Option<String>,
107 pub duration_ms: Option<u64>,
108 pub worker_id: Option<usize>,
109}
110
111impl From<&TaskState> for JobMetrics {
112 fn from(state: &TaskState) -> Self {
113 JobMetrics {
114 status: state.status.clone(),
115 created_at: state.created_at,
116 started_at: state.started_at,
117 retry_count: state.retry_count,
118 error_message: state.error_message.clone(),
119 duration_ms: state.duration_ms,
120 worker_id: state.worker_id,
121 }
122 }
123}
124
125#[derive(Debug, Clone)]
126pub(crate) struct QueuedTask {
127 pub id: String,
128 pub task_name: String,
129 pub task_data: Vec<u8>,
130 pub retry_count: u32,
131 pub created_at: std::time::Instant,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct HealthStatus {
136 pub status: String,
137 pub queue_depth: u64,
138 pub max_queue_size: usize,
139 pub timestamp: DateTime<Utc>,
140 pub accepting_tasks: bool,
141}
142
143impl HealthStatus {
144 pub fn healthy(queue_depth: u64) -> Self {
145 Self {
146 status: "healthy".to_string(),
147 queue_depth,
148 max_queue_size: MAX_QUEUE_SIZE,
149 timestamp: Utc::now(),
150 accepting_tasks: queue_depth < (MAX_QUEUE_SIZE as u64 / 2),
151 }
152 }
153
154 pub fn degraded(queue_depth: u64) -> Self {
155 Self {
156 status: "degraded".to_string(),
157 queue_depth,
158 max_queue_size: MAX_QUEUE_SIZE,
159 timestamp: Utc::now(),
160 accepting_tasks: queue_depth < MAX_QUEUE_SIZE as u64,
161 }
162 }
163
164 pub fn unhealthy(queue_depth: u64) -> Self {
165 Self {
166 status: "unhealthy".to_string(),
167 queue_depth,
168 max_queue_size: MAX_QUEUE_SIZE,
169 timestamp: Utc::now(),
170 accepting_tasks: false,
171 }
172 }
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct CachedJobResult {
177 pub job_id: String,
178 pub completed_at: DateTime<Utc>,
179 pub success: bool,
180 pub data: serde_json::Value, pub error: Option<String>, pub ttl: Option<Duration>, }