runtara_workflow_stdlib/
instance_output.rs1use serde::{Deserialize, Serialize};
12use std::path::PathBuf;
13
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(rename_all = "snake_case")]
17pub enum InstanceOutputStatus {
18 Completed,
20 Failed,
22 Suspended,
24 Sleeping,
26 Cancelled,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct InstanceOutput {
33 pub status: InstanceOutputStatus,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub result: Option<serde_json::Value>,
39
40 #[serde(skip_serializing_if = "Option::is_none")]
42 pub error: Option<String>,
43
44 #[serde(skip_serializing_if = "Option::is_none")]
46 pub checkpoint_id: Option<String>,
47
48 #[serde(skip_serializing_if = "Option::is_none")]
50 pub wake_after_ms: Option<u64>,
51}
52
53impl InstanceOutput {
54 pub fn completed(result: serde_json::Value) -> Self {
56 Self {
57 status: InstanceOutputStatus::Completed,
58 result: Some(result),
59 error: None,
60 checkpoint_id: None,
61 wake_after_ms: None,
62 }
63 }
64
65 pub fn failed(error: impl Into<String>) -> Self {
67 Self {
68 status: InstanceOutputStatus::Failed,
69 result: None,
70 error: Some(error.into()),
71 checkpoint_id: None,
72 wake_after_ms: None,
73 }
74 }
75
76 pub fn suspended(checkpoint_id: impl Into<String>) -> Self {
78 Self {
79 status: InstanceOutputStatus::Suspended,
80 result: None,
81 error: None,
82 checkpoint_id: Some(checkpoint_id.into()),
83 wake_after_ms: None,
84 }
85 }
86
87 pub fn sleeping(checkpoint_id: impl Into<String>, wake_after_ms: u64) -> Self {
89 Self {
90 status: InstanceOutputStatus::Sleeping,
91 result: None,
92 error: None,
93 checkpoint_id: Some(checkpoint_id.into()),
94 wake_after_ms: Some(wake_after_ms),
95 }
96 }
97
98 pub fn cancelled() -> Self {
100 Self {
101 status: InstanceOutputStatus::Cancelled,
102 result: None,
103 error: None,
104 checkpoint_id: None,
105 wake_after_ms: None,
106 }
107 }
108
109 pub fn write_to_output_file(&self) -> std::io::Result<()> {
116 let path = get_output_file_path();
117 self.write_to_file(&path)
118 }
119
120 pub fn write_to_file(&self, path: &std::path::Path) -> std::io::Result<()> {
122 let content = serde_json::to_string_pretty(self)?;
123 if let Some(parent) = path.parent() {
124 std::fs::create_dir_all(parent)?;
125 }
126 std::fs::write(path, content)
127 }
128}
129
130pub fn get_output_file_path() -> PathBuf {
134 PathBuf::from("/data/output.json")
135}
136
137pub fn write_completed(result: serde_json::Value) -> std::io::Result<()> {
139 InstanceOutput::completed(result).write_to_output_file()
140}
141
142pub fn write_failed(error: impl Into<String>) -> std::io::Result<()> {
144 InstanceOutput::failed(error).write_to_output_file()
145}
146
147pub fn write_suspended(checkpoint_id: impl Into<String>) -> std::io::Result<()> {
149 InstanceOutput::suspended(checkpoint_id).write_to_output_file()
150}
151
152pub fn write_sleeping(checkpoint_id: impl Into<String>, wake_after_ms: u64) -> std::io::Result<()> {
154 InstanceOutput::sleeping(checkpoint_id, wake_after_ms).write_to_output_file()
155}
156
157pub fn write_cancelled() -> std::io::Result<()> {
159 InstanceOutput::cancelled().write_to_output_file()
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165
166 #[test]
167 fn test_serialize_completed() {
168 let output = InstanceOutput::completed(serde_json::json!({"key": "value"}));
169 let json = serde_json::to_string(&output).unwrap();
170 assert!(json.contains("\"status\":\"completed\""));
171 assert!(json.contains("\"result\""));
172 }
173
174 #[test]
175 fn test_serialize_sleeping() {
176 let output = InstanceOutput::sleeping("checkpoint-1", 3600000);
177 let json = serde_json::to_string(&output).unwrap();
178 assert!(json.contains("\"status\":\"sleeping\""));
179 assert!(json.contains("\"checkpoint_id\":\"checkpoint-1\""));
180 assert!(json.contains("\"wake_after_ms\":3600000"));
181 }
182
183 #[test]
184 fn test_serialize_cancelled() {
185 let output = InstanceOutput::cancelled();
186 let json = serde_json::to_string(&output).unwrap();
187 assert!(json.contains("\"status\":\"cancelled\""));
188 }
189}