简体   繁体   中英

Singleton saga in MassTransit

What I'm trying to do is to create only one saga instance, not updated by subsequent events. So for example if I send EventA at 09:00, with CorrelationId equal to 979158a2-dfa0-45f0-9107-8b8b8028bb9f and then the saga for that event is still alive at 10:00, then if at 10:00 I send another instance of EventA with the same CorrelationId that was sent previously, I don't want it to overwrite the previous saga state but instead I would like this event to be ignored by MT. I kind of achieved that, because my saga state is not overriden (only its version is incremented), but the problem is that MT throws an error when the new event arrives. The exception is (+one log entry above it):

[18:41:12 DBG] SAGA:App.Services.Communicators.Amazon.Dispatcher.Api.Sagas.GetOrdersState:0368a723-a819-450f-b6e5-9211d1d6a3a9 Dupe App.Services.Financial.Contracts.GetOrdersCommand
MongoDB.Driver.MongoWriteException: A write operation resulted in an error.
  E11000 duplicate key error collection: Dispatcher.get.orders.states index: _id_ dup key: { _id: BinData(3, 23A7680319A80F45B6E59211D1D6A3A9) }
 ---> MongoDB.Driver.MongoBulkWriteException`1[App.Services.Communicators.Amazon.Dispatcher.Api.Sagas.GetOrdersState]: A bulk write operation resulted in one or more errors.
  E11000 duplicate key error collection: Dispatcher.get.orders.states index: _id_ dup key: { _id: BinData(3, 23A7680319A80F45B6E59211D1D6A3A9) }
   at MongoDB.Driver.MongoCollectionImpl`1.BulkWriteAsync(IClientSessionHandle session, IEnumerable`1 requests, BulkWriteOptions options, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionImpl`1.UsingImplicitSessionAsync[TResult](Func`2 funcAsync, CancellationToken cancellationToken)
   at MongoDB.Driver.MongoCollectionBase`1.InsertOneAsync(TDocument document, InsertOneOptions options, Func`3 bulkWriteAsync)
   --- End of inner exception stack trace ---
   at MongoDB.Driver.MongoCollectionBase`1.InsertOneAsync(TDocument document, InsertOneOptions options, Func`3 bulkWriteAsync)
   at MassTransit.MongoDbIntegration.Saga.Context.MongoDbSagaRepositoryContext`2.Insert(TSaga instance)

And the important part of the saga config:

Event(() => GetOrdersIntegrationEventReceived, e =>
    e
        .CorrelateById(x => x.Message.CorrelationId)
        .SelectId(x => x.Message.CorrelationId)
        .SetSagaFactory(ctx => new GetOrdersState
        {
            CorrelationId = ctx.Message.CorrelationId,
            PartnerId = ctx.Message.PartnerId,
            LastUpdatedBeforeFromRequest = ctx.Message.LastUpdatedBefore
        })
        .InsertOnInitial = true);

Is what I'm trying to do even possible?

MassTransit will only create one instance of the saga for each CorrelationId , so your reasoning is correct. However, you're approach is a little off and could use some tweaking.

For instance, your event configuration:

Event(() => GetOrdersIntegrationEventReceived, e => e.CorrelateById(x => x.Message.CorrelationId));

That's it, all the extra stuff is why you're seeing messages in the debug log.

Then, after the event is declared:

During(Initial, Created,
    When(GetOrdersIntegrationEventReceived)
        .Then(context =>
        {
            context.Instance.PartnerId = context.Message.PartnerId,
            context.Instance.LastUpdatedBeforeFromRequest = context.Message.LastUpdatedBefore
        })
        .TransitionTo(Created)
);

That's it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM