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}
51
52impl fmt::Display for TaskStatus {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match self {
55 TaskStatus::Queued => write!(f, "queued"),
56 TaskStatus::InProgress => write!(f, "in_progress"),
57 TaskStatus::Completed => write!(f, "completed"),
58 TaskStatus::Failed => write!(f, "failed"),
59 TaskStatus::Retrying => write!(f, "retrying"),
60 }
61 }
62}
63
64#[derive(Debug, Clone, Serialize, Deserialize)]
65pub struct TaskState {
66 pub id: String,
67 pub task_name: String,
68 pub task_data: serde_json::Value,
69 pub status: TaskStatus,
70 pub retry_count: u32,
71 pub created_at: DateTime<Utc>,
72 pub started_at: Option<DateTime<Utc>>,
73 pub completed_at: Option<DateTime<Utc>>,
74 pub duration_ms: Option<u64>,
75 pub error_message: Option<String>,
76 pub worker_id: Option<usize>,
77}
78
79impl TaskState {
80 pub fn is_terminal(&self) -> bool {
81 matches!(self.status, TaskStatus::Completed | TaskStatus::Failed)
82 }
83
84 pub fn can_retry(&self) -> bool {
85 self.retry_count < MAX_RETRIES
86 && matches!(self.status, TaskStatus::Failed)
87 && self
88 .error_message
89 .as_ref()
90 .is_some_and(|msg| !msg.contains("permanent"))
91 }
92
93 pub fn age(&self) -> chrono::Duration {
94 Utc::now().signed_duration_since(self.created_at)
95 }
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct JobMetrics {
100 pub status: TaskStatus,
101 pub created_at: DateTime<Utc>,
102 pub started_at: Option<DateTime<Utc>>,
103 pub retry_count: u32,
104 pub error_message: Option<String>,
105 pub duration_ms: Option<u64>,
106 pub worker_id: Option<usize>,
107}
108
109impl From<&TaskState> for JobMetrics {
110 fn from(state: &TaskState) -> Self {
111 JobMetrics {
112 status: state.status.clone(),
113 created_at: state.created_at,
114 started_at: state.started_at,
115 retry_count: state.retry_count,
116 error_message: state.error_message.clone(),
117 duration_ms: state.duration_ms,
118 worker_id: state.worker_id,
119 }
120 }
121}
122
123#[derive(Debug, Clone)]
124pub(crate) struct QueuedTask {
125 pub id: String,
126 pub task_name: String,
127 pub task_data: Vec<u8>,
128 pub retry_count: u32,
129 pub created_at: std::time::Instant,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct HealthStatus {
134 pub status: String,
135 pub queue_depth: u64,
136 pub max_queue_size: usize,
137 pub timestamp: DateTime<Utc>,
138 pub accepting_tasks: bool,
139}
140
141impl HealthStatus {
142 pub fn healthy(queue_depth: u64) -> Self {
143 Self {
144 status: "healthy".to_string(),
145 queue_depth,
146 max_queue_size: MAX_QUEUE_SIZE,
147 timestamp: Utc::now(),
148 accepting_tasks: queue_depth < (MAX_QUEUE_SIZE as u64 / 2),
149 }
150 }
151
152 pub fn degraded(queue_depth: u64) -> Self {
153 Self {
154 status: "degraded".to_string(),
155 queue_depth,
156 max_queue_size: MAX_QUEUE_SIZE,
157 timestamp: Utc::now(),
158 accepting_tasks: queue_depth < MAX_QUEUE_SIZE as u64,
159 }
160 }
161
162 pub fn unhealthy(queue_depth: u64) -> Self {
163 Self {
164 status: "unhealthy".to_string(),
165 queue_depth,
166 max_queue_size: MAX_QUEUE_SIZE,
167 timestamp: Utc::now(),
168 accepting_tasks: false,
169 }
170 }
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct CachedJobResult {
175 pub job_id: String,
176 pub completed_at: DateTime<Utc>,
177 pub success: bool,
178 pub data: serde_json::Value, pub error: Option<String>, pub ttl: Option<Duration>, }