.netmasstransit

How do I conditionally create a MassTransit saga?


I have a saga that should be triggered whenever one of two events occur. However, if a condition in the database isn't fulfilled, no saga should be created.

I've tried something like this, but it seems like a saga instance is persisted to the database, but with default (empty) values. So it seems like the if-statement is kind of working, it's just that a saga is created anyway.

I guess I'm not doing it right, but I'm unsure where I should plug in the condition?

Using MassTransit version 8.0.8

public MySaga()
{
    InstanceState(x => x.CurrentState, Processing);

    Event(() => EventOne, x => x.CorrelateById(context => context.Message.TransactionId));
    Event(() => EventTwo, x => x.CorrelateById(context => context.Message.TransactionId));

    Initially(
        When(EventOne)
            .IfAsync(async context => await ShouldCreateSaga(context),
                x => x
                    .Then(context =>
                    {
                        context.Saga.TransactionId = context.Message.TransactionId;
                    })
                    .TransitionTo(Processing)
            ),
        When(EventTwo)
            .IfAsync(async context => await ShouldCreateSaga(context),
                x => x
                    .Then(context =>
                    {
                        context.Saga.TransactionId = context.Message.TransactionId;
                    })
                    .TransitionTo(Processing)
            )
    );

    ...
}

private static async Task<bool> ShouldCreateSaga(PipeContext context)
{
    var serviceProvider = context.GetPayload<IServiceProvider>();
    var dbContext = serviceProvider.GetRequiredService<DbContext>();
    return await dbContext.SomeTable.AnyAsync(x => x.CreateSaga);
}

Solution

  • You can use IfElse and Finalize the saga if it isn't needed.

    .IfElseAsync(async context => await ShouldCreateSaga(context),
        yes => yes
            .Then(context =>
            {
                context.Saga.TransactionId = context.Message.TransactionId;
            })
            .TransitionTo(Processing),
        no => no.Finalize()
    );
    
    // this should also be set, so that Final instances are removed
    SetCompletedWhenFinalized();