1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
9#[serde(rename_all = "lowercase")]
10pub enum RunStatus {
11 #[default]
13 Queued,
14 Claimed,
16 Running,
18 Success,
20 Failed,
22 Canceled,
24 Timeout,
26}
27
28impl RunStatus {
29 pub const fn is_terminal(&self) -> bool {
31 matches!(
32 self,
33 Self::Success | Self::Failed | Self::Canceled | Self::Timeout
34 )
35 }
36
37 pub const fn is_active(&self) -> bool {
39 matches!(self, Self::Queued | Self::Claimed | Self::Running)
40 }
41}
42
43impl std::fmt::Display for RunStatus {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 match self {
46 Self::Queued => write!(f, "queued"),
47 Self::Claimed => write!(f, "claimed"),
48 Self::Running => write!(f, "running"),
49 Self::Success => write!(f, "success"),
50 Self::Failed => write!(f, "failed"),
51 Self::Canceled => write!(f, "canceled"),
52 Self::Timeout => write!(f, "timeout"),
53 }
54 }
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct Run {
60 pub run_id: String,
62
63 pub job_id: Option<String>,
65
66 pub script_name: String,
68
69 pub parent_run_id: Option<String>,
72
73 pub root_run_id: Option<String>,
75
76 pub child_index: Option<i32>,
78
79 pub scheduled_for: DateTime<Utc>,
82
83 pub started_at: Option<DateTime<Utc>>,
85
86 pub finished_at: Option<DateTime<Utc>>,
88
89 pub duration_ms: Option<i64>,
91
92 pub status: RunStatus,
95
96 pub attempt: i32,
98
99 pub instance_id: Option<String>,
102
103 pub placement_json: Option<Value>,
105
106 pub pool_id: Option<String>,
108
109 pub actor_json: Value,
112
113 pub params_json: Value,
115
116 pub stdout_text: Option<String>,
119
120 pub stderr_text: Option<String>,
122
123 pub error_json: Option<Value>,
125
126 pub stats_json: Option<Value>,
128
129 pub claimed_by: Option<String>,
131
132 pub claim_lease_until: Option<DateTime<Utc>>,
134}
135
136impl Run {
137 pub fn new(script_name: impl Into<String>, scheduled_for: DateTime<Utc>) -> Self {
142 Self {
143 run_id: uuid::Uuid::new_v4().to_string(),
144 job_id: None,
145 script_name: script_name.into(),
146 parent_run_id: None,
147 root_run_id: None,
148 child_index: None,
149 scheduled_for,
150 started_at: None,
151 finished_at: None,
152 duration_ms: None,
153 status: RunStatus::Queued,
154 attempt: 1,
155 instance_id: None,
156 placement_json: None,
157 pool_id: None,
158 actor_json: Value::Null,
159 params_json: Value::Object(serde_json::Map::default()),
160 stdout_text: None,
161 stderr_text: None,
162 error_json: None,
163 stats_json: None,
164 claimed_by: None,
165 claim_lease_until: None,
166 }
167 }
168
169 pub fn for_job(
171 job_id: impl Into<String>,
172 script_name: impl Into<String>,
173 scheduled_for: DateTime<Utc>,
174 ) -> Self {
175 let mut run = Self::new(script_name, scheduled_for);
176 run.job_id = Some(job_id.into());
177 run
178 }
179
180 pub fn start(&mut self) {
182 self.started_at = Some(Utc::now());
183 self.status = RunStatus::Running;
184 }
185
186 pub fn complete(&mut self) {
188 let finished = Utc::now();
189 self.finished_at = Some(finished);
190 self.status = RunStatus::Success;
191 if let Some(started) = self.started_at {
192 self.duration_ms = Some((finished - started).num_milliseconds());
193 }
194 }
195
196 pub fn fail(&mut self, error: impl Into<String>) {
198 let finished = Utc::now();
199 self.finished_at = Some(finished);
200 self.status = RunStatus::Failed;
201 self.error_json = Some(serde_json::json!({ "message": error.into() }));
202 if let Some(started) = self.started_at {
203 self.duration_ms = Some((finished - started).num_milliseconds());
204 }
205 }
206
207 pub fn timeout(&mut self, error: impl Into<String>) {
209 let finished = Utc::now();
210 self.finished_at = Some(finished);
211 self.status = RunStatus::Timeout;
212 self.error_json = Some(serde_json::json!({ "message": error.into() }));
213 if let Some(started) = self.started_at {
214 self.duration_ms = Some((finished - started).num_milliseconds());
215 }
216 }
217}