Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
using SimpleResults;
using TransactionProcessor.BusinessLogic.Requests;
using Grpc.Core;
using Xunit.Abstractions;
using Xunit.Sdk;

namespace TransactionProcessor.BusinessLogic.Tests.DomainEventHandlers
{
Expand Down
33 changes: 22 additions & 11 deletions TransactionProcessor.BusinessLogic/Common/PolicyFactory.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Threading.Tasks;
using EventStore.Client;
using Grpc.Core;
using Polly;
Expand All @@ -17,15 +18,25 @@

AsyncRetryPolicy<Result> retryPolicy = CreateRetryPolicy(retryCount, retryDelayValue, policyTag);

return withFallBack switch {
IAsyncPolicy<Result> policyWrap = withFallBack switch {

Check notice on line 21 in TransactionProcessor.BusinessLogic/Common/PolicyFactory.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

TransactionProcessor.BusinessLogic/Common/PolicyFactory.cs#L21

Replace this 'switch' expression with a ternary conditional operator to increase readability.
true => CreateFallbackPolicy(policyTag, retryPolicy),
_ => retryPolicy
};
return policyWrap;
}

public static async Task<Result> ExecuteWithPolicyAsync(Func<Task<Result>> action, IAsyncPolicy<Result> policy, String policyTag = "")

Check failure on line 28 in TransactionProcessor.BusinessLogic/Common/PolicyFactory.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

TransactionProcessor.BusinessLogic/Common/PolicyFactory.cs#L28

Use the overloading mechanism instead of the optional parameters.
{
Result result = await policy.ExecuteAsync(action);

// Log success if no retries were required
Logger.LogWarning($"{policyTag} - Execution succeeded without retries.");

return result;
}

private static AsyncRetryPolicy<Result> CreateRetryPolicy(int retryCount, TimeSpan retryDelay, String policyTag)
{
//
return Policy<Result>
.Handle<WrongExpectedVersionException>()
.Or<RpcException>(ex => ex.StatusCode == StatusCode.DeadlineExceeded)
Expand All @@ -39,15 +50,15 @@

private static AsyncPolicyWrap<Result> CreateFallbackPolicy(String policyTag, AsyncRetryPolicy<Result> retryPolicy)
{
AsyncFallbackPolicy<Result> fallbackPolicy = Policy<Result>
.Handle<WrongExpectedVersionException>()
.Or<TimeoutException>()
.FallbackAsync(async (cancellationToken) =>
{
Logger.LogWarning($"{policyTag} -All retries failed. Executing fallback action...");
// Log failure, notify monitoring system, or enqueue for later processing
return Result.Failure("Fallback action executed");
});
var fallbackPolicy = Policy<Result>
.Handle<Exception>() // Catch-all for exceptions that aren't retried
.FallbackAsync(
fallbackValue: Result.Failure("An error occurred, no retry required."), // Ensure a valid Result return
onFallbackAsync: (exception, context) =>

Check notice on line 57 in TransactionProcessor.BusinessLogic/Common/PolicyFactory.cs

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

TransactionProcessor.BusinessLogic/Common/PolicyFactory.cs#L57

'context' is not used. Use discard parameter instead.
{
Logger.LogWarning($"{policyTag} - Non-retryable exception encountered: {exception.GetType().Name}");
return Task.CompletedTask;
});

return fallbackPolicy.WrapAsync(retryPolicy);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ private async Task<Result> HandleSpecificDomainEvent(CallbackReceivedEnrichedEve
{
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "MerchantSettlementDomainEventHandler - MerchantFeeSettledEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
if (domainEvent.TypeString == typeof(CallbackHandler.DataTransferObjects.Deposit).ToString()) {
// Work out the merchant id from the reference field (second part, split on hyphen)
String merchantReference = domainEvent.Reference.Split("-")[1];
Expand All @@ -80,7 +80,7 @@ private async Task<Result> HandleSpecificDomainEvent(CallbackReceivedEnrichedEve
}

return Result.Success();
});
}, retryPolicy, "MerchantSettlementDomainEventHandler - MerchantFeeSettledEvent");
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ private async Task<Result> HandleSpecificDomainEvent(SettlementDomainEvents.Merc
CancellationToken cancellationToken) {
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "MerchantSettlementDomainEventHandler - MerchantFeeSettledEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
MerchantStatementCommands.AddSettledFeeToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.FeeCalculatedDateTime, domainEvent.CalculatedValue, domainEvent.TransactionId, domainEvent.FeeId);

return await this.Mediator.Send(command, cancellationToken);
});
}, retryPolicy, "MerchantSettlementDomainEventHandler - MerchantFeeSettledEvent");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,22 @@ private async Task<Result> HandleSpecificDomainEvent(MerchantStatementDomainEven

IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "MerchantStatementDomainEventHandler - StatementGeneratedEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
MerchantStatementCommands.EmailMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.MerchantStatementId);

return await this.Mediator.Send(command, cancellationToken);
});
}, retryPolicy, "MerchantStatementDomainEventHandler - StatementGeneratedEvent");
}

private async Task<Result> HandleSpecificDomainEvent(TransactionDomainEvents.TransactionHasBeenCompletedEvent domainEvent,
CancellationToken cancellationToken) {
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "MerchantStatementDomainEventHandler - TransactionHasBeenCompletedEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
MerchantStatementCommands.AddTransactionToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.CompletedDateTime, domainEvent.TransactionAmount, domainEvent.IsAuthorised, domainEvent.TransactionId);

return await this.Mediator.Send(command, cancellationToken);
});
},retryPolicy, "MerchantStatementDomainEventHandler - TransactionHasBeenCompletedEvent");
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,25 @@ private async Task<Result> HandleSpecificDomainEvent(FloatDomainEvents.FloatCred

IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "TransactionDomainEventHandler - FloatCreditPurchasedEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
FloatActivityCommands.RecordCreditPurchaseCommand command =
new(domainEvent.EstateId, domainEvent.FloatId,
domainEvent.CreditPurchasedDateTime, domainEvent.Amount, domainEvent.EventId);

return await this.Mediator.Send(command, cancellationToken);
});
},retryPolicy, "TransactionDomainEventHandler - FloatCreditPurchasedEvent");
}

private async Task<Result> HandleSpecificDomainEvent(TransactionDomainEvents.TransactionCostInformationRecordedEvent domainEvent, CancellationToken cancellationToken){

IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "TransactionDomainEventHandler - TransactionCostInformationRecordedEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
FloatActivityCommands.RecordTransactionCommand command = new(domainEvent.EstateId,
domainEvent.TransactionId);

return await this.Mediator.Send(command, cancellationToken);
});
}, retryPolicy, "TransactionDomainEventHandler - TransactionCostInformationRecordedEvent");
}

private async Task<Result> HandleSpecificDomainEvent(TransactionDomainEvents.TransactionHasBeenCompletedEvent domainEvent,
Expand All @@ -93,38 +93,38 @@ private async Task<Result> HandleSpecificDomainEvent(TransactionDomainEvents.Mer
CancellationToken cancellationToken) {
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "TransactionDomainEventHandler - MerchantFeePendingSettlementAddedToTransactionEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
SettlementCommands.AddMerchantFeePendingSettlementCommand command =
new SettlementCommands.AddMerchantFeePendingSettlementCommand(domainEvent.TransactionId,
domainEvent.CalculatedValue, domainEvent.FeeCalculatedDateTime,
(CalculationType)domainEvent.FeeCalculationType, domainEvent.FeeId, domainEvent.FeeValue,
domainEvent.SettlementDueDate, domainEvent.MerchantId, domainEvent.EstateId);
return await this.Mediator.Send(command, cancellationToken);
});
}, retryPolicy, "TransactionDomainEventHandler - MerchantFeePendingSettlementAddedToTransactionEvent");
}

private async Task<Result> HandleSpecificDomainEvent(TransactionDomainEvents.SettledMerchantFeeAddedToTransactionEvent domainEvent,
CancellationToken cancellationToken) {
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "TransactionDomainEventHandler - SettledMerchantFeeAddedToTransactionEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
AddSettledFeeToSettlementCommand command = new AddSettledFeeToSettlementCommand(
domainEvent.SettledDateTime.Date, domainEvent.MerchantId, domainEvent.EstateId, domainEvent.FeeId, domainEvent.TransactionId);
return await this.Mediator.Send(command, cancellationToken);
});
},retryPolicy, "TransactionDomainEventHandler - SettledMerchantFeeAddedToTransactionEvent");
}

private async Task<Result> HandleSpecificDomainEvent(SettlementDomainEvents.MerchantFeeSettledEvent domainEvent,
CancellationToken cancellationToken)
{
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(2, policyTag: "TransactionDomainEventHandler - MerchantFeeSettledEvent");

return await retryPolicy.ExecuteAsync(async () => {
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
AddSettledMerchantFeeCommand command = new(domainEvent.TransactionId, domainEvent.CalculatedValue,
domainEvent.FeeCalculatedDateTime, (CalculationType)domainEvent.FeeCalculationType, domainEvent.FeeId,
domainEvent.FeeValue, domainEvent.SettledDateTime, domainEvent.SettlementId);
return await this.Mediator.Send(command, cancellationToken);
});
}, retryPolicy, "TransactionDomainEventHandler - MerchantFeeSettledEvent");
}

private async Task<Result> HandleSpecificDomainEvent(TransactionDomainEvents.CustomerEmailReceiptRequestedEvent domainEvent,
Expand Down
Loading