pub type Result<T> = std::result::Result<T, WorkflowError>;
#[derive(Debug, thiserror::Error)]
pub enum WorkflowError {
#[error("Workflow execution error: {0}")]
Execution(String),
#[error("Workflow validation error: {0}")]
Validation(String),
#[error("Workflow scheduling error: {0}")]
Scheduling(String),
#[error("DAG error: {0}")]
Dag(#[from] DagError),
#[error("Task execution error in '{task_id}': {message}")]
TaskExecution {
task_id: String,
message: String,
},
#[error("Task '{task_id}' timed out after {timeout_secs}s")]
TaskTimeout {
task_id: String,
timeout_secs: u64,
},
#[error("Workflow state error: {0}")]
State(String),
#[error("Workflow not found: {0}")]
NotFound(String),
#[error("Workflow already exists: {0}")]
AlreadyExists(String),
#[error("Conditional expression error: {0}")]
ConditionalExpression(String),
#[error("Template error: {0}")]
Template(String),
#[error("Versioning error: {0}")]
Versioning(String),
#[error("Integration error with {service}: {message}")]
Integration {
service: String,
message: String,
},
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("Invalid cron expression: {0}")]
CronExpression(String),
#[error("Persistence error: {0}")]
Persistence(String),
#[error("Monitoring error: {0}")]
Monitoring(String),
#[error("Resource exhausted: {0}")]
ResourceExhausted(String),
#[error("Deadlock detected in workflow '{workflow_id}'")]
Deadlock {
workflow_id: String,
},
#[error("Invalid parameter '{param}': {message}")]
InvalidParameter {
param: String,
message: String,
},
#[error("Internal error: {0}")]
Internal(String),
}
#[derive(Debug, thiserror::Error)]
pub enum DagError {
#[error("Cycle detected in DAG: {0}")]
CycleDetected(String),
#[error("Invalid node ID: {0}")]
InvalidNode(String),
#[error("Invalid edge from '{from}' to '{to}': {message}")]
InvalidEdge {
from: String,
to: String,
message: String,
},
#[error("DAG is empty")]
EmptyDag,
#[error("Unreachable node: {0}")]
UnreachableNode(String),
#[error("Missing dependency: {0}")]
MissingDependency(String),
}
impl WorkflowError {
pub fn execution<S: Into<String>>(msg: S) -> Self {
Self::Execution(msg.into())
}
pub fn validation<S: Into<String>>(msg: S) -> Self {
Self::Validation(msg.into())
}
pub fn scheduling<S: Into<String>>(msg: S) -> Self {
Self::Scheduling(msg.into())
}
pub fn state<S: Into<String>>(msg: S) -> Self {
Self::State(msg.into())
}
pub fn not_found<S: Into<String>>(id: S) -> Self {
Self::NotFound(id.into())
}
pub fn already_exists<S: Into<String>>(id: S) -> Self {
Self::AlreadyExists(id.into())
}
pub fn task_execution<S1: Into<String>, S2: Into<String>>(task_id: S1, message: S2) -> Self {
Self::TaskExecution {
task_id: task_id.into(),
message: message.into(),
}
}
pub fn task_timeout<S: Into<String>>(task_id: S, timeout_secs: u64) -> Self {
Self::TaskTimeout {
task_id: task_id.into(),
timeout_secs,
}
}
pub fn conditional<S: Into<String>>(msg: S) -> Self {
Self::ConditionalExpression(msg.into())
}
pub fn template<S: Into<String>>(msg: S) -> Self {
Self::Template(msg.into())
}
pub fn versioning<S: Into<String>>(msg: S) -> Self {
Self::Versioning(msg.into())
}
pub fn integration<S1: Into<String>, S2: Into<String>>(service: S1, message: S2) -> Self {
Self::Integration {
service: service.into(),
message: message.into(),
}
}
pub fn cron_expression<S: Into<String>>(msg: S) -> Self {
Self::CronExpression(msg.into())
}
pub fn persistence<S: Into<String>>(msg: S) -> Self {
Self::Persistence(msg.into())
}
pub fn monitoring<S: Into<String>>(msg: S) -> Self {
Self::Monitoring(msg.into())
}
pub fn resource_exhausted<S: Into<String>>(msg: S) -> Self {
Self::ResourceExhausted(msg.into())
}
pub fn deadlock<S: Into<String>>(workflow_id: S) -> Self {
Self::Deadlock {
workflow_id: workflow_id.into(),
}
}
pub fn invalid_parameter<S1: Into<String>, S2: Into<String>>(param: S1, message: S2) -> Self {
Self::InvalidParameter {
param: param.into(),
message: message.into(),
}
}
pub fn internal<S: Into<String>>(msg: S) -> Self {
Self::Internal(msg.into())
}
}
impl DagError {
pub fn cycle<S: Into<String>>(path: S) -> Self {
Self::CycleDetected(path.into())
}
pub fn invalid_node<S: Into<String>>(node_id: S) -> Self {
Self::InvalidNode(node_id.into())
}
pub fn invalid_edge<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
from: S1,
to: S2,
message: S3,
) -> Self {
Self::InvalidEdge {
from: from.into(),
to: to.into(),
message: message.into(),
}
}
pub fn missing_dependency<S: Into<String>>(dep: S) -> Self {
Self::MissingDependency(dep.into())
}
}