From b3584b5e5ba2c2a7ed794135b2dee5dd817a0fcb Mon Sep 17 00:00:00 2001 From: StuartFerguson Date: Thu, 28 Aug 2025 17:50:38 +0100 Subject: [PATCH] add retry to MerchantFeeSettledEvent --- ...erchantStatementDomainEventHandlerTests.cs | 32 ++++++++++++++ .../MerchantStatementDomainEventHandler.cs | 43 ++++++++++++++----- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/MerchantStatementDomainEventHandlerTests.cs b/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/MerchantStatementDomainEventHandlerTests.cs index 572e351f..198f8a2f 100644 --- a/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/MerchantStatementDomainEventHandlerTests.cs +++ b/TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/MerchantStatementDomainEventHandlerTests.cs @@ -22,6 +22,7 @@ public class MerchantStatementDomainEventHandlerTests : DomainEventHandlerTests public MerchantStatementDomainEventHandlerTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { this.EventHandler = new MerchantStatementDomainEventHandler(this.Mediator.Object); + Logger.Initialise(new NullLogger()); } [Fact] @@ -64,6 +65,37 @@ public async Task MerchantStatementDomainEventHandler_Handle_MerchantFeeSettledE result.IsSuccess.ShouldBeTrue(); } + [Fact] + public async Task MerchantStatementDomainEventHandler_Handle_MerchantFeeSettledEvent_WrongExpectedRetried_EventIsHandled() + { + List errors = new() { "WrongExpectedVersion" }; + + this.Mediator.SetupSequence(m => m.Send(It.IsAny>(), It.IsAny())) + .ReturnsAsync(Result.Failure(errors)) + .ReturnsAsync(Result.Success()); + + Result result = await this.EventHandler.Handle(TestData.DomainEvents.MerchantFeeSettledEvent, CancellationToken.None); + result.IsSuccess.ShouldBeTrue(); + this.Mediator.Verify(m => m.Send(It.IsAny>(), It.IsAny()), Times.Exactly(2)); + } + + [Fact] + public async Task MerchantStatementDomainEventHandler_Handle_MerchantFeeSettledEvent_WrongExpectedRetried_AllRetriesFailed() + { + List errors = new() { "WrongExpectedVersion" }; + this.Mediator.SetupSequence(m => m.Send(It.IsAny>(), It.IsAny())) + .ReturnsAsync(Result.Failure(errors)) + .ReturnsAsync(Result.Failure(errors)) + .ReturnsAsync(Result.Failure(errors)) + .ReturnsAsync(Result.Failure(errors)) + .ReturnsAsync(Result.Failure(errors)) + .ReturnsAsync(Result.Failure(errors)); + + Result result = await this.EventHandler.Handle(TestData.DomainEvents.MerchantFeeSettledEvent, CancellationToken.None); + result.IsFailed.ShouldBeTrue(); + this.Mediator.Verify(m => m.Send(It.IsAny>(), It.IsAny()), Times.Exactly(6)); + } + [Fact] public async Task MerchantStatementDomainEventHandler_Handle_StatementCreatedForDateEvent_EventIsHandled() { diff --git a/TransactionProcessor.BusinessLogic/EventHandling/MerchantStatementDomainEventHandler.cs b/TransactionProcessor.BusinessLogic/EventHandling/MerchantStatementDomainEventHandler.cs index a13ec2d1..d8ad31b5 100644 --- a/TransactionProcessor.BusinessLogic/EventHandling/MerchantStatementDomainEventHandler.cs +++ b/TransactionProcessor.BusinessLogic/EventHandling/MerchantStatementDomainEventHandler.cs @@ -1,22 +1,23 @@ -using System; -using MediatR; +using MediatR; using Polly; +using Prometheus; using Shared.DomainDrivenDesign.EventSourcing; +using Shared.EventStore.Aggregate; using Shared.EventStore.EventHandling; +using Shared.Exceptions; +using Shared.Logger; +using Shared.ValueObjects; using SimpleResults; +using System; using System.Diagnostics; using System.IO; using System.Net.Http; using System.Threading; using System.Threading.Tasks; -using Prometheus; -using Shared.Logger; using TransactionProcessor.BusinessLogic.Common; using TransactionProcessor.BusinessLogic.Requests; using TransactionProcessor.BusinessLogic.Services; using TransactionProcessor.DomainEvents; -using Shared.EventStore.Aggregate; -using Shared.ValueObjects; namespace TransactionProcessor.BusinessLogic.EventHandling { @@ -144,12 +145,32 @@ private async Task HandleSpecificDomainEvent(MerchantDomainEvents.Withdr private async Task HandleSpecificDomainEvent(SettlementDomainEvents.MerchantFeeSettledEvent domainEvent, CancellationToken cancellationToken) { - MerchantStatementCommands.AddSettledFeeToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.FeeCalculatedDateTime, - PositiveMoney.Create(Money.Create(domainEvent.CalculatedValue)), domainEvent.TransactionId, domainEvent.FeeId); + IAsyncPolicy retryPolicy = PolicyFactory.CreatePolicy(policyTag: "MerchantStatementDomainEventHandler - HandleSpecificDomainEvent"); + + try + { + return await PolicyFactory.ExecuteWithPolicyAsync(async () => + { + MerchantStatementCommands.AddSettledFeeToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.FeeCalculatedDateTime, + PositiveMoney.Create(Money.Create(domainEvent.CalculatedValue)), domainEvent.TransactionId, domainEvent.FeeId); + + Result result = await this.Mediator.Send(command, cancellationToken); + return result; + + }, retryPolicy, "MerchantStatementDomainEventHandler - HandleSpecificDomainEvent"); + } + catch (Exception ex) + { + return Result.Failure(ex.GetExceptionMessages()); + } + //MerchantStatementCommands.AddSettledFeeToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.FeeCalculatedDateTime, + // PositiveMoney.Create(Money.Create(domainEvent.CalculatedValue)), domainEvent.TransactionId, domainEvent.FeeId); + + ////return await this.Mediator.Send(command, cancellationToken); + //Result result = await this.Mediator.Send(command, cancellationToken); + //return result; + - //return await this.Mediator.Send(command, cancellationToken); - Result result = await this.Mediator.Send(command, cancellationToken); - return result; } #endregion