use std::fmt;
use async_trait::async_trait;
use crate::database::Session;
#[derive(Debug)]
pub enum SagaError {
ExecutionFailed(String),
CompensationFailed(String),
Timeout(String),
}
impl fmt::Display for SagaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::ExecutionFailed(msg) => write!(f, "Saga execution failed: {msg}"),
Self::CompensationFailed(msg) => write!(f, "Saga compensation failed: {msg}"),
Self::Timeout(msg) => write!(f, "Saga timeout: {msg}"),
}
}
}
impl std::error::Error for SagaError {}
impl crate::i18n::error_ext::LocalizedMsg for SagaError {
fn message_key(&self) -> &'static str {
match self {
Self::ExecutionFailed(_) => "saga-execution-failed",
Self::CompensationFailed(_) => "saga-compensation-failed",
Self::Timeout(_) => "saga-timeout",
}
}
fn message_args(&self) -> Vec<(&str, String)> {
match self {
Self::ExecutionFailed(reason) => vec![("reason", reason.clone())],
Self::CompensationFailed(reason) => vec![("reason", reason.clone())],
Self::Timeout(reason) => vec![("reason", reason.clone())],
}
}
}
#[async_trait]
pub trait SagaAction: Send + Sync {
async fn execute(&self, session: &Session) -> Result<(), SagaError>;
fn name(&self) -> &str;
}
pub struct SagaStep {
pub name: String,
pub shard_id: u32,
pub action: Box<dyn SagaAction>,
pub compensation: Box<dyn SagaAction>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SagaStatus {
Running,
Completed,
Compensating,
Failed,
CompensationFailed,
}
impl SagaStatus {
pub fn as_str(&self) -> &'static str {
match self {
SagaStatus::Running => "running",
SagaStatus::Completed => "completed",
SagaStatus::Compensating => "compensating",
SagaStatus::Failed => "failed",
SagaStatus::CompensationFailed => "compensation_failed",
}
}
pub fn from_str_kind(s: &str) -> SagaStatus {
match s {
"completed" => SagaStatus::Completed,
"compensating" => SagaStatus::Compensating,
"failed" => SagaStatus::Failed,
"compensation_failed" | "compensation-failed" => SagaStatus::CompensationFailed,
_ => SagaStatus::Running,
}
}
}
#[derive(Debug, Clone)]
pub struct SagaStepLog {
pub name: String,
pub shard_id: u32,
pub action_success: bool,
pub compensation_success: Option<bool>,
pub error: Option<String>,
}