cloacina_workflow/
error.rs

1/*
2 *  Copyright 2025 Colliery Software
3 *
4 *  Licensed under the Apache License, Version 2.0 (the "License");
5 *  you may not use this file except in compliance with the License.
6 *  You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 *  Unless required by applicable law or agreed to in writing, software
11 *  distributed under the License is distributed on an "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 *  See the License for the specific language governing permissions and
14 *  limitations under the License.
15 */
16
17//! # Error Types
18//!
19//! This module defines the minimal error types needed for workflow authoring.
20//! These errors do not include database or runtime-specific variants, which
21//! are defined in the main `cloacina` crate.
22//!
23//! ## Error Types
24//!
25//! - [`ContextError`]: Errors related to context operations
26//! - [`TaskError`]: Errors that occur during task execution
27//! - [`CheckpointError`]: Errors in task checkpointing
28
29use chrono::{DateTime, Utc};
30use thiserror::Error;
31
32/// Errors that can occur during context operations.
33///
34/// This minimal version only includes errors that can occur without database
35/// or runtime dependencies.
36#[derive(Debug, Error)]
37pub enum ContextError {
38    /// JSON serialization/deserialization error
39    #[error("Serialization error: {0}")]
40    Serialization(#[from] serde_json::Error),
41
42    /// Key not found in context
43    #[error("Key not found: {0}")]
44    KeyNotFound(String),
45
46    /// Type mismatch when retrieving a value
47    #[error("Type mismatch for key {0}")]
48    TypeMismatch(String),
49
50    /// Key already exists when inserting
51    #[error("Key already exists: {0}")]
52    KeyExists(String),
53}
54
55/// Errors that can occur during task execution.
56///
57/// Task errors encompass execution failures, context issues, and
58/// any other problems that prevent a task from completing successfully.
59#[derive(Debug, Error)]
60pub enum TaskError {
61    /// Task execution failed with a message
62    #[error("Task execution failed: {message}")]
63    ExecutionFailed {
64        message: String,
65        task_id: String,
66        timestamp: DateTime<Utc>,
67    },
68
69    /// Task dependency not satisfied
70    #[error("Task dependency not satisfied: {dependency} required by {task_id}")]
71    DependencyNotSatisfied { dependency: String, task_id: String },
72
73    /// Task exceeded timeout
74    #[error("Task timeout: {task_id} exceeded {timeout_seconds}s")]
75    Timeout {
76        task_id: String,
77        timeout_seconds: u64,
78    },
79
80    /// Context operation error within a task
81    #[error("Context error in task {task_id}: {error}")]
82    ContextError {
83        task_id: String,
84        error: ContextError,
85    },
86
87    /// Task validation failed
88    #[error("Task validation failed: {message}")]
89    ValidationFailed { message: String },
90
91    /// Unknown error
92    #[error("Unknown error in task {task_id}: {message}")]
93    Unknown { task_id: String, message: String },
94
95    /// Task readiness check failed
96    #[error("Task readiness check failed: {task_id}")]
97    ReadinessCheckFailed { task_id: String },
98
99    /// Trigger rule evaluation failed
100    #[error("Trigger rule evaluation failed: {task_id}")]
101    TriggerRuleFailed { task_id: String },
102}
103
104impl From<ContextError> for TaskError {
105    fn from(error: ContextError) -> Self {
106        TaskError::ContextError {
107            task_id: "unknown".to_string(),
108            error,
109        }
110    }
111}
112
113/// Errors that can occur during task checkpointing.
114///
115/// Checkpoint errors occur when tasks attempt to save intermediate state
116/// for recovery purposes.
117#[derive(Debug, Error)]
118pub enum CheckpointError {
119    /// Failed to save checkpoint
120    #[error("Failed to save checkpoint for task {task_id}: {message}")]
121    SaveFailed { task_id: String, message: String },
122
123    /// Failed to load checkpoint
124    #[error("Failed to load checkpoint for task {task_id}: {message}")]
125    LoadFailed { task_id: String, message: String },
126
127    /// Checkpoint serialization error
128    #[error("Checkpoint serialization error: {0}")]
129    Serialization(#[from] serde_json::Error),
130
131    /// Checkpoint storage error
132    #[error("Checkpoint storage error: {message}")]
133    StorageError { message: String },
134
135    /// Checkpoint validation failed
136    #[error("Checkpoint validation failed: {message}")]
137    ValidationFailed { message: String },
138}