Simple Saga Usage

Component: NServiceBus | Nuget: NServiceBus (Version: 6.x)

Code walk-through

This sample shows a simple saga.

At startup the sample will send two StartOrder messages with different identifers for OrderId. This will cause two saga instances to start because StartOrder is configured to start a saga using the IAmStartedByMessages construct. There is also a mapping defined between StartOrder.OrderId and OrderSagaData.OrderId. This mapping helps to correlate incoming messages to its appropriate saga instances.

This sample also requests a 30 minute CancelOrder timeout that will mark the saga as complete if the saga is not already complete.

The output to the console will be

2015-02-11 22:34:59.475 INFO  OrderSaga Saga with OrderId 1 received StartOrder with OrderId 1
2015-02-11 22:34:59.526 INFO  OrderSaga Saga with OrderId 2 received StartOrder with OrderId 2
2015-02-11 22:34:59.572 INFO  OrderSaga Saga with OrderId 1 received CompleteOrder with OrderId 1
2015-02-11 22:34:59.606 INFO  OrderSaga Saga with OrderId 2 received CompleteOrder with OrderId 2

The Saga

Edit
public class OrderSaga :
    Saga<OrderSagaData>,
    IAmStartedByMessages<StartOrder>,
    IHandleMessages<CompleteOrder>,
    IHandleTimeouts<CancelOrder>
{
    static ILog log = LogManager.GetLogger<OrderSaga>();

    protected override void ConfigureHowToFindSaga(SagaPropertyMapper<OrderSagaData> mapper)
    {
        mapper.ConfigureMapping<StartOrder>(message => message.OrderId)
                .ToSaga(sagaData => sagaData.OrderId);
        mapper.ConfigureMapping<CompleteOrder>(message => message.OrderId)
                .ToSaga(sagaData => sagaData.OrderId);
    }

    public async Task Handle(StartOrder message, IMessageHandlerContext context)
    {
        Data.OrderId = message.OrderId;
        log.Info($"Saga with OrderId {Data.OrderId} received StartOrder with OrderId {message.OrderId}");
        var completeOrder = new CompleteOrder
        {
            OrderId = Data.OrderId
        };
        await context.SendLocal(completeOrder)
            .ConfigureAwait(false);
        await RequestTimeout<CancelOrder>(context, TimeSpan.FromMinutes(30))
            .ConfigureAwait(false);
    }

    public Task Handle(CompleteOrder message, IMessageHandlerContext context)
    {
        log.Info($"Saga with OrderId {Data.OrderId} received CompleteOrder with OrderId {message.OrderId}");
        MarkAsComplete();
        return Task.CompletedTask;
    }

    public Task Timeout(CancelOrder state, IMessageHandlerContext context)
    {
        log.Info($"Complete not received soon enough OrderId {Data.OrderId}");
        MarkAsComplete();
        return Task.CompletedTask;
    }
}

Related Articles

  • Sagas
    NServiceBus uses event-driven architecture to include fault-tolerance and scalability in long-term business processes.

Last modified