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}