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