pub struct SagaCtx<'a> {
pub(crate) state: &'a AppState,
pub(crate) saga_id: u64,
pub(crate) step_index: AtomicU32,
pub(crate) forward_step_stack: Mutex<Vec<u32>>,
}Expand description
Read-only context passed to a saga’s inner async function. Wraps the AppState handle and the saga’s allocated id.
Construct via SagaCtx::new — the durability log requires the
per-step counter to start at zero and be owned by the ctx (so
concurrent sagas don’t interleave step indices).
Fields§
§state: &'a AppState§saga_id: u64§step_index: AtomicU32Monotonic step index (0, 1, 2, …) for this saga. Each
dispatch / compensate call fetch_add(1)s and writes the
resulting index into the saga log. Atomic because saga inner
futures may parallelise dispatches in the future (today they
don’t, but the cost is one cache line).
forward_step_stack: Mutex<Vec<u32>>(codex P1 PR #636 round 4.) Stack of forward-step indices that
have completed successfully and are eligible to be undone by
the next compensate call. dispatch pushes on success;
compensate pops to determine which original forward step
it’s reversing, and marks that step compensated in the log.
Without this, in-process compensation only writes new
compensated rows at fresh indices; the original succeeded
rows stay succeeded, so resume-on-restart re-replays them
and either no-ops or worse double-applies the inverse.
Mutex<Vec> (rather than a lock-free counter) because saga
inner futures could in theory parallelize compensations; in
practice they’re serial today, so contention is zero.
Implementations§
Source§impl<'a> SagaCtx<'a>
impl<'a> SagaCtx<'a>
Sourcepub fn new(state: &'a AppState, saga_id: u64) -> Self
pub fn new(state: &'a AppState, saga_id: u64) -> Self
Construct a fresh context for a saga that has just allocated
its saga_id (via alloc_saga_id).
Sourcepub fn saga_id(&self) -> u64
pub fn saga_id(&self) -> u64
Saga-id this context belongs to. Used by sagas that need to log progress with the saga prefix.
Sourcepub async fn state_lock(&self) -> MutexGuard<'_, State>
pub async fn state_lock(&self) -> MutexGuard<'_, State>
Acquire the reducer’s state lock for read-only inspection. Used by sagas that need to inspect post-step state to decide the next step (e.g. RestoreTornOffTab checking whether the source workspace is now empty before issuing the cascade delete). Hold briefly — the reducer is single-mutex.
Sourcepub async fn dispatch(&self, cmd: Command) -> Result<Vec<Event>, String>
pub async fn dispatch(&self, cmd: Command) -> Result<Vec<Event>, String>
Dispatch cmd through the srv reducer and apply the emitted
events to SQLite + the broadcast bus, exactly like the
in-handler reducer-dispatch helpers.
Returns the emitted event vec on success. If the reducer
emits any Event::Error, the error message is returned and
SQLite/bus side-effects are skipped — the caller must then
dispatch compensation for the saga’s already-applied steps.
Sourcepub async fn compensate(&self, cmd: Command)
pub async fn compensate(&self, cmd: Command)
Best-effort compensating dispatch. Same as dispatch but
SQLite-write failures are logged and swallowed. Intended for
the unwind path: the saga is already returning an error to
the caller; throwing on cleanup hides the original cause and
prevents subsequent compensating commands from running.
Auto Trait Implementations§
impl<'a> !Freeze for SagaCtx<'a>
impl<'a> !RefUnwindSafe for SagaCtx<'a>
impl<'a> Send for SagaCtx<'a>
impl<'a> Sync for SagaCtx<'a>
impl<'a> Unpin for SagaCtx<'a>
impl<'a> !UnwindSafe for SagaCtx<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.