Skip to main content

SagaExecutor

Struct SagaExecutor 

Source
pub struct SagaExecutor { /* private fields */ }
Expand description

Saga forward phase executor

Executes saga steps sequentially during the forward phase. Coordinates with saga store to persist state and handle failures.

Implementations§

Source§

impl SagaExecutor

Source

pub fn new() -> Self

Create a new saga executor without a saga store

This is suitable for testing. For production, use with_store().

Source

pub fn with_store(store: Arc<PostgresSagaStore>) -> Self

Create a new saga executor with a saga store

This enables persistence of saga state and recovery from failures.

Source

pub fn has_store(&self) -> bool

Check if executor has a saga store configured

Source

pub async fn execute_step( &self, saga_id: Uuid, step_number: u32, mutation_name: &str, _variables: &Value, subgraph: &str, ) -> SagaStoreResult<StepExecutionResult>

Execute a single saga step

Executes a single mutation step within a saga, handling:

  • Step state validation (Pending → Executing → Completed)
  • @requires field pre-fetching from owning subgraphs
  • Entity data augmentation with required fields
  • Mutation execution via MutationExecutor
  • Result capture and persistence
§Arguments
  • saga_id - ID of saga being executed
  • step_number - Step number to execute (1-indexed, 1 = first step)
  • mutation_name - GraphQL mutation operation name
  • variables - Input variables for the mutation (JSON value)
  • subgraph - Target subgraph name (must exist in federation)
§Returns

StepExecutionResult with:

  • success: true if step executed successfully
  • data: Result entity data if successful
  • error: Error description if failed
  • duration_ms: Execution time for monitoring
§Errors

Returns SagaStoreError if:

  • Saga not found in store
  • Step already executed (not in Pending state)
  • Subgraph unavailable
  • Mutation execution fails
  • @requires fields cannot be fetched
§Example
let executor = SagaExecutor::new();
let result = executor.execute_step(
    saga_id,
    1,
    "createOrder",
    &json!({"customerId": "c123", "total": 100.0}),
    "orders-service"
).await?;

if result.success {
    println!("Order created with data: {:?}", result.data);
} else {
    eprintln!("Step failed: {}", result.error.unwrap());
    // Compensation will be triggered by coordinator
}
Source

pub async fn execute_saga( &self, saga_id: Uuid, ) -> SagaStoreResult<Vec<StepExecutionResult>>

Execute all steps in a saga sequentially

§Arguments
  • saga_id - ID of saga to execute
§Returns

Vector of step results (successful or failed)

Source

pub async fn get_execution_state( &self, saga_id: Uuid, ) -> SagaStoreResult<ExecutionState>

Get current execution state of saga

§Arguments
  • saga_id - ID of saga
§Returns

Current execution state including completed steps

Trait Implementations§

Source§

impl Default for SagaExecutor

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more