Saga Orchestrator in Rust
struct SagaOrchestrator<S: SagaStore> {
steps: Vec<Box<dyn SagaStep>>,
store: S,
}
#[async_trait]
trait SagaStep: Send + Sync {
async fn execute(&self, ctx: &SagaContext) -> Result<StepOutput, StepError>;
async fn compensate(&self, ctx: &SagaContext) -> Result<(), StepError>;
fn name(&self) -> &str;
}
impl<S: SagaStore> SagaOrchestrator<S> {
async fn run(&self, saga_id: Uuid, input: Value) -> Result<SagaOutput, SagaError> {
let mut ctx = SagaContext::new(saga_id, input);
for (i, step) in self.steps.iter().enumerate() {
self.store.record_step_start(saga_id, step.name()).await?;
match step.execute(&ctx).await {
Ok(output) => { ctx.add_output(step.name(), output); }
Err(e) => { return self.compensate_from(saga_id, i, &ctx).await; }
}
}
Ok(ctx.into_output())
}
}