Skip to main content

stormchaser_model/
workflow.rs

1//! Core workflow run and state management types.
2
3use crate::id::*;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8use utoipa::ToSchema;
9
10/// The overall status of a workflow run.
11#[derive(
12    Debug, Serialize, Deserialize, Clone, sqlx::Type, PartialEq, Eq, ToSchema, schemars::JsonSchema,
13)]
14#[sqlx(type_name = "run_status", rename_all = "snake_case")]
15#[serde(rename_all = "snake_case")]
16pub enum RunStatus {
17    /// The run has been queued but not yet processed.
18    Queued,
19    /// The run's source code and dependencies are being resolved.
20    Resolving,
21    /// The run is ready but waiting for resources to start.
22    StartPending,
23    /// The run is actively executing.
24    Running,
25    /// The run completed successfully.
26    Succeeded,
27    /// The run encountered a fatal error.
28    Failed,
29    /// The run was aborted by a user or system event.
30    Aborted,
31}
32
33impl From<String> for RunStatus {
34    fn from(s: String) -> Self {
35        match s.as_str() {
36            "resolving" => RunStatus::Resolving,
37            "start_pending" => RunStatus::StartPending,
38            "running" => RunStatus::Running,
39            "succeeded" => RunStatus::Succeeded,
40            "failed" => RunStatus::Failed,
41            "aborted" => RunStatus::Aborted,
42            _ => RunStatus::Queued,
43        }
44    }
45}
46
47impl From<RunStatus> for String {
48    fn from(s: RunStatus) -> Self {
49        match s {
50            RunStatus::Queued => "queued".to_string(),
51            RunStatus::Resolving => "resolving".to_string(),
52            RunStatus::StartPending => "start_pending".to_string(),
53            RunStatus::Running => "running".to_string(),
54            RunStatus::Succeeded => "succeeded".to_string(),
55            RunStatus::Failed => "failed".to_string(),
56            RunStatus::Aborted => "aborted".to_string(),
57        }
58    }
59}
60
61/// Details of a specific workflow run execution.
62#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow)]
63pub struct WorkflowRun {
64    /// Unique identifier for the workflow run.
65    pub id: RunId,
66    /// The name of the workflow.
67    pub workflow_name: String,
68    /// Identifier of the user or system that initiated the run.
69    pub initiating_user: String,
70    /// The repository URL containing the workflow source.
71    pub repo_url: String,
72    /// The file path to the workflow definition within the repository.
73    pub workflow_path: String,
74    /// The Git reference (branch, tag, or commit) being executed.
75    pub git_ref: String,
76    /// Current status of the run.
77    pub status: RunStatus,
78    /// Version number used for optimistic concurrency control.
79    pub version: i32, // For Optimistic Concurrency Control
80    /// Monotonically increasing token for fencing state updates.
81    pub fencing_token: i64, // Monotonically increasing token
82    /// Timestamp when the run was created.
83    pub created_at: DateTime<Utc>,
84    /// Timestamp when the run was last updated.
85    pub updated_at: DateTime<Utc>,
86    /// Timestamp when the run began resolving dependencies.
87    pub started_resolving_at: Option<DateTime<Utc>>,
88    /// Timestamp when the run actually started executing steps.
89    pub started_at: Option<DateTime<Utc>>,
90    /// Timestamp when the run finished execution (success, failure, or aborted).
91    pub finished_at: Option<DateTime<Utc>>,
92    /// Optional error message if the run failed.
93    pub error: Option<String>,
94}
95
96/// Execution context for a workflow run.
97#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow)]
98pub struct RunContext {
99    /// Associated workflow run ID.
100    pub run_id: RunId,
101    /// Version of the DSL the workflow was written in.
102    pub dsl_version: String,
103    /// Full parsed abstract syntax tree of the workflow definition.
104    pub workflow_definition: Value, // Full parsed AST
105    /// Original unparsed workflow file content.
106    pub source_code: String, // Original workflow file content
107    /// JSON inputs provided at trigger-time.
108    pub inputs: Value, // Trigger-time inputs
109    /// Decrypted map of secrets available to this run.
110    pub secrets: Value, // Decrypted secrets map
111    /// Registry of sensitive values that must be redacted from logs and outputs.
112    pub sensitive_values: Vec<String>, // Redaction registry
113}
114
115/// Resource quotas associated with a workflow run.
116#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow)]
117pub struct RunQuotas {
118    /// Associated workflow run ID.
119    pub run_id: RunId,
120    /// Maximum number of concurrent steps allowed.
121    pub max_concurrency: i32,
122    /// Maximum CPU limit for the overall run.
123    pub max_cpu: String,
124    /// Maximum memory limit for the overall run.
125    pub max_memory: String,
126    /// Maximum storage limit for the overall run.
127    pub max_storage: String,
128    /// Maximum duration before the run times out.
129    pub timeout: String,
130    /// Current accumulated CPU usage of the run.
131    pub current_cpu_usage: f64,
132    /// Current accumulated memory usage of the run.
133    pub current_memory_usage: String,
134}
135
136/// Audit log entry for tracking workflow events.
137#[derive(Debug, Serialize, Deserialize, Clone, sqlx::FromRow)]
138pub struct AuditLog {
139    /// Unique identifier for the audit log entry.
140    pub id: i64,
141    /// Associated workflow run ID.
142    pub run_id: RunId,
143    /// The type of event that occurred (e.g., 'workflow_started', 'step_failed').
144    pub event_type: String, // e.g., "workflow_started", "step_failed", "approval_granted"
145    /// The identifier of the user or system process that caused the event.
146    pub actor: String, // User ID or system process
147    /// Additional context or metadata about the event.
148    pub payload: Value,
149    /// Timestamp when the event was recorded.
150    pub created_at: DateTime<Utc>,
151}
152
153#[cfg(test)]
154mod tests {
155    use super::*;
156
157    #[test]
158    fn test_run_status_from_string() {
159        assert_eq!(
160            RunStatus::from("resolving".to_string()),
161            RunStatus::Resolving
162        );
163        assert_eq!(
164            RunStatus::from("start_pending".to_string()),
165            RunStatus::StartPending
166        );
167        assert_eq!(RunStatus::from("running".to_string()), RunStatus::Running);
168        assert_eq!(
169            RunStatus::from("succeeded".to_string()),
170            RunStatus::Succeeded
171        );
172        assert_eq!(RunStatus::from("failed".to_string()), RunStatus::Failed);
173        assert_eq!(RunStatus::from("aborted".to_string()), RunStatus::Aborted);
174        assert_eq!(RunStatus::from("queued".to_string()), RunStatus::Queued);
175        assert_eq!(RunStatus::from("unknown".to_string()), RunStatus::Queued);
176    }
177
178    #[test]
179    fn test_run_status_to_string() {
180        assert_eq!(String::from(RunStatus::Queued), "queued");
181        assert_eq!(String::from(RunStatus::Resolving), "resolving");
182        assert_eq!(String::from(RunStatus::StartPending), "start_pending");
183        assert_eq!(String::from(RunStatus::Running), "running");
184        assert_eq!(String::from(RunStatus::Succeeded), "succeeded");
185        assert_eq!(String::from(RunStatus::Failed), "failed");
186        assert_eq!(String::from(RunStatus::Aborted), "aborted");
187    }
188}