snatch-dev / Chronicle

Implementation of saga pattern for .NET Core
MIT License
397 stars 70 forks source link

Reusing Saga Coordinator #52

Open royayan1988 opened 4 years ago

royayan1988 commented 4 years ago

How do I reuse the coordinator. I tried to use the Reject functionality and it's working fine. But the next time unable to use the coordinator in subsequent request. I can see the state as Rejected.

GooRiOn commented 4 years ago

Since the saga has been marked as rejected, you cannot call it anymore. Otherwise you could end up with inconsistent state. What exact behavior would you expect?

NSemaX commented 3 years ago

When once rejected state has occurred,in new order created request saga flow not working properly. Example ,first order request comes Handle(OrderCreated @event) calls related OrderCreated Handle then calls ProductReserved Handle method, in example scenario when product reserved occurs an error so ReserveProductRejected Handle is called. Reject(); calls it's CompensateAsync(ReserveProductRejected method then other compansate method. Untill now its every thing is ok but if there is another order request comes with same scenario only OrderCreated handler called by saga coordinator.ReserveProductRejected handle method not calling.

public class ApproveOrderHandler : IIntegrationEventHandler, IIntegrationEventHandler, IIntegrationEventHandler, IIntegrationEventHandler, IIntegrationEventHandler, IIntegrationEventHandler, IIntegrationEventHandler { private readonly ISagaCoordinator _sagaCoordinator;

    public ApproveOrderHandler(ISagaCoordinator sagaCoordinator)
    {
        _sagaCoordinator = sagaCoordinator;
    }

    public Task Handle(OrderCreated @event)
        => _sagaCoordinator.ProcessAsync(@event, _sagaContext);
    public Task Handle(ProductReserved @event)
        => _sagaCoordinator.ProcessAsync(@event, _sagaContext);
    public Task Handle(ReserveProductRejected @event)
        => _sagaCoordinator.ProcessAsync(@event, _sagaContext);

...

}

public class ApproveOrderSaga : Saga, ISagaStartAction, ISagaAction, ISagaAction, ISagaAction, ISagaAction, ISagaAction, ISagaAction { private readonly ISagaIntegrationEventService _sagaIntegrationEventService; private readonly ISagaPatternRepository _sagaPatternRepository;

    public ApproveOrderSaga(ISagaIntegrationEventService sagaIntegrationEventService, ISagaPatternRepository sagaPatternRepository)
    {
        _sagaIntegrationEventService = sagaIntegrationEventService;
        _sagaPatternRepository = sagaPatternRepository;
    }

    public async Task HandleAsync(OrderCreated message, ISagaContext context)
    {
        var orderCreatedIntegrationEvent = new ReserveProduct(message.ColerationId,message.ProductId, message.OrderId);

        await _sagaIntegrationEventService.PublishThroughEventBusAsync(orderCreatedIntegrationEvent);
        await _sagaIntegrationEventService.AddAndSaveEventAsync(orderCreatedIntegrationEvent);

        await _sagaPatternRepository.Add(new Models.SagaEvent { ColerationId = message.ColerationId, Description = "OrderCreated Handle Event", CreatedDate = DateTime.Now, StatusId = 1 });

    }

    public async Task CompensateAsync(OrderCreated message, ISagaContext context)
    {
        var orderCreatedIntegrationEvent = new RevokeOrder(message.ColerationId, message.OrderId);

        await _sagaIntegrationEventService.PublishThroughEventBusAsync(orderCreatedIntegrationEvent);
        await _sagaIntegrationEventService.AddAndSaveEventAsync(orderCreatedIntegrationEvent);

        await _sagaPatternRepository.Add(new Models.SagaEvent { ColerationId = message.ColerationId, Description = "OrderCreated Compensate Event", CreatedDate = DateTime.Now, StatusId = 1 });
    }

    public async Task HandleAsync(ProductReserved message, ISagaContext context)
    {
        var IntegrationEvent = new ApproveOrder(message.ColerationId, message.OrderId);

        await _sagaIntegrationEventService.PublishThroughEventBusAsync(IntegrationEvent);
        await _sagaIntegrationEventService.AddAndSaveEventAsync(IntegrationEvent);

        await _sagaPatternRepository.Add(new Models.SagaEvent { ColerationId = message.ColerationId, Description = "Product Reserved Handle Event", CreatedDate = DateTime.Now, StatusId = 1 });
    }

    public async Task CompensateAsync(ProductReserved message, ISagaContext context)
    {
        var IntegrationEvent = new ReleaseProduct(message.ColerationId, message.ProductId, message.OrderId);

        await _sagaIntegrationEventService.PublishThroughEventBusAsync(IntegrationEvent);
        await _sagaIntegrationEventService.AddAndSaveEventAsync(IntegrationEvent);

        await _sagaPatternRepository.Add(new Models.SagaEvent { ColerationId = message.ColerationId, Description = "Product Reserved Compensate Event", CreatedDate = DateTime.Now, StatusId = 1 });
    }

    public async Task HandleAsync(ReserveProductRejected message, ISagaContext context)
    {
        await _sagaPatternRepository.Add(new Models.SagaEvent { ColerationId = message.ColerationId, Description = "ReserveProductRejected Handle Event", CreatedDate = DateTime.Now, StatusId = 1 });
        Reject();
        await Task.CompletedTask;
    }

    public async Task CompensateAsync(ReserveProductRejected message, ISagaContext context)
    {
        await _sagaPatternRepository.Add(new Models.SagaEvent { ColerationId = message.ColerationId, Description = "ReserveProductRejected Compensate Event", CreatedDate = DateTime.Now, StatusId = 1 });
        await Task.CompletedTask;
    }

... }