Skip to main content

changeset_saga/
step.rs

1/// A step in a saga that can be executed and compensated.
2///
3/// Each step transforms an input into an output, with the ability to undo
4/// its effects if a later step fails. The input is stored for compensation.
5///
6/// # Type Parameters
7///
8/// - `Input`: Data received from the previous step (or saga entry point)
9/// - `Output`: Data produced for the next step
10/// - `Context`: Shared dependencies (injected, not passed between steps)
11/// - `Error`: The error type for step failures
12pub trait SagaStep: Send + Sync {
13    /// Data received from the previous step or saga entry point.
14    type Input: Clone + Send + 'static;
15
16    /// Data produced for the next step.
17    type Output: Clone + Send + 'static;
18
19    /// Shared context providing dependencies.
20    type Context;
21
22    /// Error type for step failures.
23    type Error;
24
25    /// Human-readable name for logging and error messages.
26    fn name(&self) -> &'static str;
27
28    /// Execute the step, transforming input into output.
29    ///
30    /// # Errors
31    ///
32    /// Returns an error if the step fails to complete.
33    fn execute(&self, ctx: &Self::Context, input: Self::Input)
34    -> Result<Self::Output, Self::Error>;
35
36    /// Compensate (undo) the step's effects.
37    ///
38    /// Called during rollback when a later step fails. Receives the original
39    /// input that was passed to `execute()`.
40    ///
41    /// The default implementation is a no-op, suitable for read-only steps.
42    ///
43    /// # Errors
44    ///
45    /// Returns an error if compensation fails.
46    fn compensate(&self, ctx: &Self::Context, input: Self::Input) -> Result<(), Self::Error> {
47        let _ = (ctx, input);
48        Ok(())
49    }
50
51    /// Human-readable description of what compensation will do.
52    fn compensation_description(&self) -> String {
53        format!("undo {}", self.name())
54    }
55}