Skip to main content

assay_workflow/
types.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3use std::str::FromStr;
4use utoipa::ToSchema;
5
6// ── Workflow Status ─────────────────────────────────────────
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
9#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
10pub enum WorkflowStatus {
11    Pending,
12    Running,
13    Waiting,
14    Completed,
15    Failed,
16    Cancelled,
17    TimedOut,
18}
19
20impl fmt::Display for WorkflowStatus {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        match self {
23            Self::Pending => write!(f, "PENDING"),
24            Self::Running => write!(f, "RUNNING"),
25            Self::Waiting => write!(f, "WAITING"),
26            Self::Completed => write!(f, "COMPLETED"),
27            Self::Failed => write!(f, "FAILED"),
28            Self::Cancelled => write!(f, "CANCELLED"),
29            Self::TimedOut => write!(f, "TIMED_OUT"),
30        }
31    }
32}
33
34impl FromStr for WorkflowStatus {
35    type Err = String;
36
37    fn from_str(s: &str) -> Result<Self, Self::Err> {
38        match s {
39            "PENDING" => Ok(Self::Pending),
40            "RUNNING" => Ok(Self::Running),
41            "WAITING" => Ok(Self::Waiting),
42            "COMPLETED" => Ok(Self::Completed),
43            "FAILED" => Ok(Self::Failed),
44            "CANCELLED" => Ok(Self::Cancelled),
45            "TIMED_OUT" => Ok(Self::TimedOut),
46            _ => Err(format!("unknown workflow status: {s}")),
47        }
48    }
49}
50
51impl WorkflowStatus {
52    pub fn is_terminal(self) -> bool {
53        matches!(
54            self,
55            Self::Completed | Self::Failed | Self::Cancelled | Self::TimedOut
56        )
57    }
58}
59
60// ── Activity Status ─────────────────────────────────────────
61
62#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
63#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
64pub enum ActivityStatus {
65    Pending,
66    Running,
67    Completed,
68    Failed,
69    Cancelled,
70}
71
72impl fmt::Display for ActivityStatus {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        match self {
75            Self::Pending => write!(f, "PENDING"),
76            Self::Running => write!(f, "RUNNING"),
77            Self::Completed => write!(f, "COMPLETED"),
78            Self::Failed => write!(f, "FAILED"),
79            Self::Cancelled => write!(f, "CANCELLED"),
80        }
81    }
82}
83
84impl FromStr for ActivityStatus {
85    type Err = String;
86
87    fn from_str(s: &str) -> Result<Self, Self::Err> {
88        match s {
89            "PENDING" => Ok(Self::Pending),
90            "RUNNING" => Ok(Self::Running),
91            "COMPLETED" => Ok(Self::Completed),
92            "FAILED" => Ok(Self::Failed),
93            "CANCELLED" => Ok(Self::Cancelled),
94            _ => Err(format!("unknown activity status: {s}")),
95        }
96    }
97}
98
99// ── Event Types ─────────────────────────────────────────────
100
101#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
102pub enum EventType {
103    WorkflowStarted,
104    ActivityScheduled,
105    ActivityCompleted,
106    ActivityFailed,
107    TimerStarted,
108    TimerFired,
109    SignalReceived,
110    WorkflowCompleted,
111    WorkflowFailed,
112    WorkflowCancelled,
113    ChildWorkflowStarted,
114    ChildWorkflowCompleted,
115    SideEffectRecorded,
116}
117
118impl fmt::Display for EventType {
119    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120        let s = serde_json::to_value(self)
121            .ok()
122            .and_then(|v| v.as_str().map(String::from))
123            .unwrap_or_else(|| format!("{self:?}"));
124        write!(f, "{s}")
125    }
126}
127
128impl FromStr for EventType {
129    type Err = String;
130
131    fn from_str(s: &str) -> Result<Self, Self::Err> {
132        serde_json::from_value(serde_json::Value::String(s.to_string()))
133            .map_err(|_| format!("unknown event type: {s}"))
134    }
135}
136
137// ── Overlap Policy ──────────────────────────────────────────
138
139#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
140#[serde(rename_all = "snake_case")]
141pub enum OverlapPolicy {
142    Skip,
143    Queue,
144    CancelOld,
145    AllowAll,
146}
147
148impl fmt::Display for OverlapPolicy {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        match self {
151            Self::Skip => write!(f, "skip"),
152            Self::Queue => write!(f, "queue"),
153            Self::CancelOld => write!(f, "cancel_old"),
154            Self::AllowAll => write!(f, "allow_all"),
155        }
156    }
157}
158
159impl FromStr for OverlapPolicy {
160    type Err = String;
161
162    fn from_str(s: &str) -> Result<Self, Self::Err> {
163        match s {
164            "skip" => Ok(Self::Skip),
165            "queue" => Ok(Self::Queue),
166            "cancel_old" => Ok(Self::CancelOld),
167            "allow_all" => Ok(Self::AllowAll),
168            _ => Err(format!("unknown overlap policy: {s}")),
169        }
170    }
171}
172
173// ── Records ─────────────────────────────────────────────────
174
175#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
176pub struct WorkflowRecord {
177    pub id: String,
178    pub namespace: String,
179    pub run_id: String,
180    pub workflow_type: String,
181    pub task_queue: String,
182    pub status: String,
183    pub input: Option<String>,
184    pub result: Option<String>,
185    pub error: Option<String>,
186    pub parent_id: Option<String>,
187    pub claimed_by: Option<String>,
188    pub created_at: f64,
189    pub updated_at: f64,
190    pub completed_at: Option<f64>,
191}
192
193#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
194pub struct WorkflowEvent {
195    pub id: Option<i64>,
196    pub workflow_id: String,
197    pub seq: i32,
198    pub event_type: String,
199    pub payload: Option<String>,
200    pub timestamp: f64,
201}
202
203/// Options for scheduling an activity. All fields default to sensible values
204/// when not provided by the caller; this keeps the per-call API short while
205/// still letting workflows tune retry/timeout policy when they need to.
206#[derive(Clone, Debug, Default, Serialize, Deserialize, ToSchema)]
207pub struct ScheduleActivityOpts {
208    pub max_attempts: Option<i32>,
209    pub initial_interval_secs: Option<f64>,
210    pub backoff_coefficient: Option<f64>,
211    pub start_to_close_secs: Option<f64>,
212    pub heartbeat_timeout_secs: Option<f64>,
213}
214
215#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
216pub struct WorkflowActivity {
217    pub id: Option<i64>,
218    pub workflow_id: String,
219    pub seq: i32,
220    pub name: String,
221    pub task_queue: String,
222    pub input: Option<String>,
223    pub status: String,
224    pub result: Option<String>,
225    pub error: Option<String>,
226    pub attempt: i32,
227    pub max_attempts: i32,
228    pub initial_interval_secs: f64,
229    pub backoff_coefficient: f64,
230    pub start_to_close_secs: f64,
231    pub heartbeat_timeout_secs: Option<f64>,
232    pub claimed_by: Option<String>,
233    pub scheduled_at: f64,
234    pub started_at: Option<f64>,
235    pub completed_at: Option<f64>,
236    pub last_heartbeat: Option<f64>,
237}
238
239#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
240pub struct WorkflowTimer {
241    pub id: Option<i64>,
242    pub workflow_id: String,
243    pub seq: i32,
244    pub fire_at: f64,
245    pub fired: bool,
246}
247
248#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
249pub struct WorkflowSignal {
250    pub id: Option<i64>,
251    pub workflow_id: String,
252    pub name: String,
253    pub payload: Option<String>,
254    pub consumed: bool,
255    pub received_at: f64,
256}
257
258#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
259pub struct WorkflowSchedule {
260    pub name: String,
261    pub namespace: String,
262    pub workflow_type: String,
263    pub cron_expr: String,
264    pub input: Option<String>,
265    pub task_queue: String,
266    pub overlap_policy: String,
267    pub paused: bool,
268    pub last_run_at: Option<f64>,
269    pub next_run_at: Option<f64>,
270    pub last_workflow_id: Option<String>,
271    pub created_at: f64,
272}
273
274#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
275pub struct WorkflowWorker {
276    pub id: String,
277    pub namespace: String,
278    pub identity: String,
279    pub task_queue: String,
280    pub workflows: Option<String>,
281    pub activities: Option<String>,
282    pub max_concurrent_workflows: i32,
283    pub max_concurrent_activities: i32,
284    pub active_tasks: i32,
285    pub last_heartbeat: f64,
286    pub registered_at: f64,
287}
288
289#[derive(Clone, Debug, Serialize, Deserialize)]
290pub struct WorkflowSnapshot {
291    pub workflow_id: String,
292    pub event_seq: i32,
293    pub state_json: String,
294    pub created_at: f64,
295}