Saga Overview

The ability to orchestrate a series of events is a powerful feature, and MassTransit makes this possible.

A saga is a long-lived transaction managed by a coordinator. Sagas are initiated by an event, sagas orchestrate events, and sagas maintain the state of the overall transaction. Sagas are designed to manage the complexity of a distributed transaction without locking and immediate consistency. They manage state and track any compensations required if a partial failure occurs.

We didn't create it, we learned it from the original Princeton paper and from Arnon Rotem-Gal-Oz's description.

State Machine Sagas

MassTransit includes Automatonymous, which provides a powerful state machine syntax to create sagas. This approach is highly recommended when using MassTransit.

Consumer Sagas

MassTransit supports consumer sagas, which implement one or more interfaces to consume correlated saga events. This support is included so that it is easy to move applications from other saga implementations to MassTransit.

Definitions

Saga definitions are used to specify the behavior of consumers so that they can be automatically configured. Definitions may be explicitly added by AddSaga or discovered automatically using any of the AddSagas methods.

An example saga definition is shown below. For a complete configuration reference, see the configuration section.

public class OrderStateDefinition :
    SagaDefinition<OrderState>
{
    public OrderStateDefinition()
    {
        // specify the message limit at the endpoint level, which influences
        // the endpoint prefetch count, if supported
        Endpoint(e => e.ConcurrentMessageLimit = 16);
    }

    protected override void ConfigureSaga(IReceiveEndpointConfigurator endpointConfigurator, ISagaConfigurator<OrderState> sagaConfigurator)
    {
        var partition = endpointConfigurator.CreatePartitioner(16);

        sagaConfigurator.Message<SubmitOrder>(x => x.UsePartitioner(partition, m => m.Message.CorrelationId));
        sagaConfigurator.Message<OrderAccepted>(x => x.UsePartitioner(partition, m => m.Message.CorrelationId));
        sagaConfigurator.Message<OrderCanceled>(x => x.UsePartitioner(partition, m => m.Message.CorrelationId));
    }
}

Guidance

To address some common questions related to sagas, retries, Outbox, and concurrency, this page has been compiled.