3
votes

I am encountering an "optimistic concurrency violation" exception when using NServiceBus saga.

My saga covers a relatively simple flow: when any message arrives it makes few external requests and after some time gathers replies.

Below you can find an example of my saga.

Is it a normal behavior for NServiceBus to produce the "optimistic concurrency violation" exception for such flow?

Should I consider redesigning the saga somehow?

class MySaga: SqlSaga<SagaData>, ...
{
    CorrelationPropertyName => nameof(SagaData.UserId);

    public Task Handle(StartSagaMessage message, IMessageHandlerContext context)
    {
        // save a new item id
        Data.Items.Add(message.ItemId);

        // make an external request for the item title
        context.Send<GetItemTitle>(message.ItemId);
        // make an external request for the item description
        context.Send<GetItemDescription>(message.ItemId);

        // gather results after one hour
        RequestTimeout<RequestTimeout>(TimeSpan.FromHours(1));
    }

    // this method sometimes raises "optimistic concurrency violation" exception
    public Task Handle(GetItemTitleResponse message, IMessageHandlerContext context)
    {
        Data.ItemTitles[message.ItemId] = message.ItemTitle;
    }

    // this method sometimes raises "optimistic concurrency violation" exception
    public Task Handle(GetItemDescriptionResponse message, IMessageHandlerContext context)
    {
        Data.ItemDescriptions[message.ItemId] = message.ItemDescription;
    }

    public Task Handle(RequestTimeout state, IMessageHandlerContext context)
    {
       context.Send<ProcessItems>(Data.Items, Data.ItemTitles, Data.ItemDescriptions);
       MarkAsComplete();
    }
}

I am using:

  • NServiceBus 6.4.2
  • NServiceBus.RabbitMQ
  • NServiceBus.Persistence.Sql
1

1 Answers

5
votes

Is it a normal behavior for NServiceBus to produce the "optimistic concurrency violation" exception for such flow?

Absolutely. If more than a single message correlated with the same Saga instance arrives and trying to update saga instance data simultaneaously, persistence will detect it and throw this exception. You shouldn't worry about it as recoverability feature (NServiceBus retries) will take of it. In case you have recoverability disabled, you might want to turn in on.

Should I consider redesigning the saga somehow?

If there's a very high load on your saga then you could look into options layed out in this blog post.