1use std::time::{Duration, SystemTime};
4
5use serde::{Deserialize, Serialize};
6use uuid::Uuid;
7
8use crate::{
9 common::{Label, LabelFilter, TimeRange},
10 executions::{ExecutionDetails, ExecutionId, ExecutionStatus},
11 executors::ExecutorId,
12 schedules::ScheduleId,
13};
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
17#[repr(transparent)]
18pub struct JobId(pub Uuid);
19
20impl std::fmt::Display for JobId {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 write!(f, "{}", self.0)
23 }
24}
25
26impl From<Uuid> for JobId {
27 fn from(value: Uuid) -> Self {
28 Self(value)
29 }
30}
31
32impl From<JobId> for Uuid {
33 fn from(value: JobId) -> Self {
34 value.0
35 }
36}
37
38#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
53#[repr(transparent)]
54#[serde(transparent)]
55pub struct JobTypeId(String);
56
57impl std::fmt::Display for JobTypeId {
58 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59 write!(f, "{}", self.0)
60 }
61}
62
63impl JobTypeId {
64 pub fn new<S: Into<String>>(s: S) -> Result<Self, InvalidJobTypeId> {
66 let s = s.into();
67
68 if !Self::validate(&s) {
69 return Err(InvalidJobTypeId(s));
70 }
71
72 Ok(Self(s))
73 }
74
75 pub fn new_unchecked<S: Into<String>>(s: S) -> Self {
78 Self(s.into())
79 }
80
81 fn validate(s: &str) -> bool {
82 if s.is_empty() {
83 return false;
84 }
85
86 let segments = s.split('.');
87
88 for segment in segments {
89 if segment.is_empty() {
90 return false;
91 }
92
93 let mut chars = segment.bytes();
94
95 match chars.next() {
96 Some(c) if c.is_ascii_alphabetic() => {}
97 _ => return false,
98 }
99
100 for c in chars {
101 if !(c.is_ascii_alphanumeric() || c == b'_') {
102 return false;
103 }
104 }
105 }
106
107 true
108 }
109
110 #[must_use]
112 pub fn as_str(&self) -> &str {
113 &self.0
114 }
115
116 #[must_use]
118 pub fn into_inner(self) -> String {
119 self.0
120 }
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct InvalidJobTypeId(pub String);
126
127impl std::fmt::Display for InvalidJobTypeId {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 write!(f, r#"invalid job type ID: "{}""#, self.0)
130 }
131}
132
133impl core::error::Error for InvalidJobTypeId {}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct JobType {
138 pub id: JobTypeId,
140 pub description: Option<String>,
142 pub input_schema_json: Option<String>,
144 pub output_schema_json: Option<String>,
146}
147
148#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct JobDefinition {
151 pub job_type_id: JobTypeId,
153 pub target_execution_time: SystemTime,
155 pub input_payload_json: String,
157 pub labels: Vec<Label>,
159 pub timeout_policy: TimeoutPolicy,
161 pub retry_policy: RetryPolicy,
163}
164
165#[derive(Debug, Clone, Serialize, Deserialize)]
167pub struct JobDetails {
168 pub id: JobId,
170 pub job: JobDefinition,
172 pub created_at: SystemTime,
174 pub executions: Vec<ExecutionDetails>,
176 pub schedule_id: Option<ScheduleId>,
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct TimeoutPolicy {
183 pub timeout: Duration,
187 pub base_time: TimeoutBaseTime,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
193pub enum TimeoutBaseTime {
194 TargetExecutionTime,
196 StartTime,
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct RetryPolicy {
203 pub retries: u64,
207}
208
209#[derive(Debug, Default, Clone, Serialize, Deserialize)]
211pub struct JobFilters {
212 pub job_ids: Option<Vec<JobId>>,
214 pub job_type_ids: Option<Vec<JobTypeId>>,
216 pub executor_ids: Option<Vec<ExecutorId>>,
218 pub execution_ids: Option<Vec<ExecutionId>>,
220 pub execution_statuses: Option<Vec<ExecutionStatus>>,
222 pub target_execution_time: Option<TimeRange>,
224 pub created_at: Option<TimeRange>,
226 pub labels: Option<Vec<LabelFilter>>,
228 pub schedule_ids: Option<Vec<ScheduleId>>,
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
234pub enum JobOrderBy {
235 TargetExecutionTimeAsc,
237 TargetExecutionTimeDesc,
239 CreatedAtAsc,
241 CreatedAtDesc,
243}
244
245pub struct NewJob {
247 pub job: JobDefinition,
249 pub schedule_id: Option<ScheduleId>,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct CancelledJob {
256 pub job_id: JobId,
258 pub last_execution_id: ExecutionId,
260}