Skip to content

Commit f55d7b4

Browse files
Merge pull request #775 from TransactionProcessing/task/#744_stream_management_improvements
some performance changes
2 parents 1ae1d32 + 2adfcdf commit f55d7b4

11 files changed

+136
-222
lines changed

TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/MerchantSettlementDomainEventHandlerTests.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,5 @@ public async Task MerchantSettlementDomainEventHandler_Handle_MerchantFeeSettled
4040
Result result = await this.EventHandler.Handle(TestData.DomainEvents.MerchantFeeSettledEvent, CancellationToken.None);
4141
result.IsSuccess.ShouldBeTrue();
4242
}
43-
44-
[Fact]
45-
public async Task MerchantSettlementDomainEventHandler_Handle_MerchantFeeSettledEvent_Retry_EventIsHandled()
46-
{
47-
this.Mediator.SetupSequence(m => m.Send(It.IsAny<IRequest<Result>>(), It.IsAny<CancellationToken>()))
48-
.ReturnsAsync(Result.Failure(new List<String>() { "Append failed due to WrongExpectedVersion"}))
49-
.ReturnsAsync(Result.Failure(new List<String>() { "DeadlineExceeded"}))
50-
.ReturnsAsync(Result.Success());
51-
52-
Result result = await this.EventHandler.Handle(TestData.DomainEvents.MerchantFeeSettledEvent, CancellationToken.None);
53-
result.IsSuccess.ShouldBeTrue();
54-
}
5543
}
5644
}

TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/MerchantStatementDomainEventHandlerTests.cs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,19 +33,7 @@ public async Task MerchantStatementDomainEventHandler_Handle_StatementGeneratedE
3333
Result result = await this.EventHandler.Handle(TestData.DomainEvents.StatementGeneratedEvent, CancellationToken.None);
3434
result.IsSuccess.ShouldBeTrue();
3535
}
36-
37-
[Fact]
38-
public async Task MerchantStatementDomainEventHandler_Handle_StatementGeneratedEvent_Retry_EventIsHandled()
39-
{
40-
this.Mediator.SetupSequence(m => m.Send(It.IsAny<IRequest<Result>>(), It.IsAny<CancellationToken>()))
41-
.ReturnsAsync(Result.Failure(new List<String>() { "Append failed due to WrongExpectedVersion" }))
42-
.ReturnsAsync(Result.Failure(new List<String>() { "DeadlineExceeded" }))
43-
.ReturnsAsync(Result.Success());
44-
45-
Result result = await this.EventHandler.Handle(TestData.DomainEvents.StatementGeneratedEvent, CancellationToken.None);
46-
result.IsSuccess.ShouldBeTrue();
47-
}
48-
36+
4937
[Fact]
5038
public async Task MerchantStatementDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_EventIsHandled()
5139
{
@@ -56,15 +44,4 @@ public async Task MerchantStatementDomainEventHandler_Handle_TransactionHasBeenC
5644
result.IsSuccess.ShouldBeTrue();
5745
}
5846

59-
[Fact]
60-
public async Task MerchantStatementDomainEventHandler_Handle_TransactionHasBeenCompletedEvent_Retry_EventIsHandled()
61-
{
62-
this.Mediator.SetupSequence(m => m.Send(It.IsAny<IRequest<Result>>(), It.IsAny<CancellationToken>()))
63-
.ReturnsAsync(Result.Failure(new List<String>() { "Append failed due to WrongExpectedVersion" }))
64-
.ReturnsAsync(Result.Failure(new List<String>() { "DeadlineExceeded" }))
65-
.ReturnsAsync(Result.Success());
66-
67-
Result result = await this.EventHandler.Handle(TestData.DomainEvents.TransactionHasBeenCompletedEvent, CancellationToken.None);
68-
result.IsSuccess.ShouldBeTrue();
69-
}
7047
}

TransactionProcessor.BusinessLogic.Tests/DomainEventHandlers/TransactionDomainEventHandlerTests.cs

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ public TransactionDomainEventHandlerTests(ITestOutputHelper testOutputHelper) :
109109
[InlineData(typeof(TransactionDomainEvents.MerchantFeePendingSettlementAddedToTransactionEvent))]
110110
[InlineData(typeof(TransactionDomainEvents.SettledMerchantFeeAddedToTransactionEvent))]
111111
[InlineData(typeof(SettlementDomainEvents.MerchantFeeSettledEvent))]
112-
//[InlineData(typeof(CustomerEmailReceiptRequestedEvent))]
113-
//[InlineData(typeof(CustomerEmailReceiptResendRequestedEvent))]
112+
[InlineData(typeof(TransactionDomainEvents.CustomerEmailReceiptRequestedEvent))]
113+
[InlineData(typeof(TransactionDomainEvents.CustomerEmailReceiptResendRequestedEvent))]
114114
public async Task TransactionDomainEventHandler_EventPassedIn_EventIsHandled(Type eventType) {
115115
DomainEvent domainEvent = eventType.Name switch {
116116
nameof(FloatDomainEvents.FloatCreditPurchasedEvent) => new FloatDomainEvents.FloatCreditPurchasedEvent(TestData.FloatAggregateId, TestData.EstateId, TestData.CreditPurchasedDateTime, TestData.FloatCreditAmount, TestData.FloatCreditCostPrice),
@@ -127,39 +127,6 @@ public async Task TransactionDomainEventHandler_EventPassedIn_EventIsHandled(Typ
127127
var result = await this.TransactionDomainEventHandler.Handle(domainEvent, CancellationToken.None);
128128
result.IsSuccess.ShouldBeTrue();
129129
}
130-
131-
[Theory]
132-
[InlineData(typeof(FloatDomainEvents.FloatCreditPurchasedEvent))]
133-
[InlineData(typeof(TransactionDomainEvents.TransactionCostInformationRecordedEvent))]
134-
//[InlineData(typeof(TransactionDomainEvents.TransactionHasBeenCompletedEvent))]
135-
[InlineData(typeof(TransactionDomainEvents.MerchantFeePendingSettlementAddedToTransactionEvent))]
136-
[InlineData(typeof(TransactionDomainEvents.SettledMerchantFeeAddedToTransactionEvent))]
137-
[InlineData(typeof(SettlementDomainEvents.MerchantFeeSettledEvent))]
138-
//[InlineData(typeof(CustomerEmailReceiptRequestedEvent))]
139-
//[InlineData(typeof(CustomerEmailReceiptResendRequestedEvent))]
140-
public async Task TransactionDomainEventHandler_EventPassedIn_Retry_EventIsHandled(Type eventType)
141-
{
142-
this.Mediator.SetupSequence(m => m.Send(It.IsAny<IRequest<Result>>(), It.IsAny<CancellationToken>()))
143-
.ReturnsAsync(Result.Failure(new List<String>() { "Append failed due to WrongExpectedVersion" }))
144-
.ReturnsAsync(Result.Failure(new List<String>() { "DeadlineExceeded" }))
145-
.ReturnsAsync(Result.Success());
146-
147-
DomainEvent domainEvent = eventType.Name switch
148-
{
149-
nameof(FloatDomainEvents.FloatCreditPurchasedEvent) => new FloatDomainEvents.FloatCreditPurchasedEvent(TestData.FloatAggregateId, TestData.EstateId, TestData.CreditPurchasedDateTime, TestData.FloatCreditAmount, TestData.FloatCreditCostPrice),
150-
nameof(TransactionDomainEvents.TransactionCostInformationRecordedEvent) => TestData.TransactionCostInformationRecordedEvent,
151-
nameof(TransactionDomainEvents.TransactionHasBeenCompletedEvent) => TestData.DomainEvents.TransactionHasBeenCompletedEvent,
152-
nameof(TransactionDomainEvents.MerchantFeePendingSettlementAddedToTransactionEvent) => new TransactionDomainEvents.MerchantFeePendingSettlementAddedToTransactionEvent(TestData.TransactionId, TestData.EstateId, TestData.MerchantId, TestData.CalculatedFeeValue, 0, TestData.TransactionFeeId, TestData.TransactionFeeValue, TestData.TransactionFeeCalculateDateTime, TestData.TransactionFeeSettlementDueDate, TestData.TransactionDateTime),
153-
nameof(TransactionDomainEvents.SettledMerchantFeeAddedToTransactionEvent) => TestData.SettledMerchantFeeAddedToTransactionEvent(TestData.SettlementDate),
154-
nameof(SettlementDomainEvents.MerchantFeeSettledEvent) => new SettlementDomainEvents.MerchantFeeSettledEvent(TestData.SettlementAggregateId, TestData.EstateId, TestData.MerchantId, TestData.TransactionId, TestData.CalculatedFeeValue, 0, TestData.TransactionFeeId, TestData.TransactionFeeValue, TestData.TransactionFeeCalculateDateTime, TestData.SettlementDate),
155-
//nameof(TransactionDomainEvents.CustomerEmailReceiptRequestedEvent) => TestData.CustomerEmailReceiptRequestedEvent,
156-
//nameof(TransactionDomainEvents.CustomerEmailReceiptResendRequestedEvent) => TestData.CustomerEmailReceiptResendRequestedEvent,
157-
_ => throw new NotSupportedException($"Event {eventType.Name} not supported")
158-
};
159-
160-
var result = await this.TransactionDomainEventHandler.Handle(domainEvent, CancellationToken.None);
161-
result.IsSuccess.ShouldBeTrue();
162-
}
163130
}
164131
}
165132

TransactionProcessor.BusinessLogic/EventHandling/MerchantDomainEventHandler.cs

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -55,28 +55,23 @@ public async Task<Result> Handle(IDomainEvent domainEvent,
5555
}
5656

5757
private async Task<Result> HandleSpecificDomainEvent(CallbackReceivedEnrichedEvent domainEvent,
58-
CancellationToken cancellationToken)
59-
{
60-
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(policyTag: "MerchantSettlementDomainEventHandler - MerchantFeeSettledEvent");
61-
62-
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
63-
if (domainEvent.TypeString == typeof(CallbackHandler.DataTransferObjects.Deposit).ToString()) {
64-
// Work out the merchant id from the reference field (second part, split on hyphen)
65-
String merchantReference = domainEvent.Reference.Split("-")[1];
58+
CancellationToken cancellationToken) {
59+
if (domainEvent.TypeString == typeof(CallbackHandler.DataTransferObjects.Deposit).ToString()) {
60+
// Work out the merchant id from the reference field (second part, split on hyphen)
61+
String merchantReference = domainEvent.Reference.Split("-")[1];
6662

67-
Result<Merchant> result = await this.EstateReportingRepository.GetMerchantFromReference(domainEvent.EstateId, merchantReference, cancellationToken);
68-
if (result.IsFailed)
69-
return ResultHelpers.CreateFailure(result);
63+
Result<Merchant> result = await this.EstateReportingRepository.GetMerchantFromReference(domainEvent.EstateId, merchantReference, cancellationToken);
64+
if (result.IsFailed)
65+
return ResultHelpers.CreateFailure(result);
7066

71-
// We now need to deserialise the message from the callback
72-
CallbackHandler.DataTransferObjects.Deposit callbackMessage = JsonConvert.DeserializeObject<CallbackHandler.DataTransferObjects.Deposit>(domainEvent.CallbackMessage);
67+
// We now need to deserialise the message from the callback
68+
CallbackHandler.DataTransferObjects.Deposit callbackMessage = JsonConvert.DeserializeObject<CallbackHandler.DataTransferObjects.Deposit>(domainEvent.CallbackMessage);
7369

74-
MerchantCommands.MakeMerchantDepositCommand command = new(domainEvent.EstateId, result.Data.MerchantId, DataTransferObjects.Requests.Merchant.MerchantDepositSource.Automatic, new MakeMerchantDepositRequest { DepositDateTime = callbackMessage.DateTime, Reference = callbackMessage.Reference, Amount = callbackMessage.Amount, });
75-
return await this.Mediator.Send(command, cancellationToken);
76-
}
70+
MerchantCommands.MakeMerchantDepositCommand command = new(domainEvent.EstateId, result.Data.MerchantId, DataTransferObjects.Requests.Merchant.MerchantDepositSource.Automatic, new MakeMerchantDepositRequest { DepositDateTime = callbackMessage.DateTime, Reference = callbackMessage.Reference, Amount = callbackMessage.Amount, });
71+
return await this.Mediator.Send(command, cancellationToken);
72+
}
7773

78-
return Result.Success();
79-
}, retryPolicy, "MerchantSettlementDomainEventHandler - MerchantFeeSettledEvent");
74+
return Result.Success();
8075
}
8176

8277
#endregion

TransactionProcessor.BusinessLogic/EventHandling/MerchantSettlementDomainEventHandler.cs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
using Shared.DomainDrivenDesign.EventSourcing;
44
using Shared.EventStore.EventHandling;
55
using SimpleResults;
6+
using System;
7+
using System.Diagnostics;
68
using System.Threading;
79
using System.Threading.Tasks;
10+
using Prometheus;
811
using TransactionProcessor.BusinessLogic.Common;
912
using TransactionProcessor.BusinessLogic.Requests;
13+
using TransactionProcessor.BusinessLogic.Services;
1014
using TransactionProcessor.DomainEvents;
1115

1216
namespace TransactionProcessor.BusinessLogic.EventHandling;
@@ -20,24 +24,31 @@ public MerchantSettlementDomainEventHandler(IMediator mediator) {
2024

2125
public async Task<Result> Handle(IDomainEvent domainEvent,
2226
CancellationToken cancellationToken) {
27+
28+
Stopwatch sw = Stopwatch.StartNew();
29+
String g = domainEvent.GetType().Name;
30+
String m = this.GetType().Name;
31+
Counter counterCalls = AggregateService.GetCounterMetric($"{m}_{g}_events_processed");
32+
Histogram histogramMetric = AggregateService.GetHistogramMetric($"{m}_{g}");
33+
counterCalls.Inc();
34+
2335
Task<Result> t = domainEvent switch {
2436
SettlementDomainEvents.MerchantFeeSettledEvent mfse => this.HandleSpecificDomainEvent(mfse, cancellationToken),
2537
_ => null
2638
};
39+
40+
Result result = Result.Success();
2741
if (t != null)
28-
return await t;
29-
30-
return Result.Success();
42+
result = await t;
43+
sw.Stop();
44+
histogramMetric.Observe(sw.Elapsed.TotalSeconds);
45+
return result;
3146
}
3247

3348
private async Task<Result> HandleSpecificDomainEvent(SettlementDomainEvents.MerchantFeeSettledEvent domainEvent,
3449
CancellationToken cancellationToken) {
35-
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(policyTag: "MerchantSettlementDomainEventHandler - MerchantFeeSettledEvent");
36-
37-
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
38-
MerchantStatementCommands.AddSettledFeeToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.FeeCalculatedDateTime, domainEvent.CalculatedValue, domainEvent.TransactionId, domainEvent.FeeId);
50+
MerchantStatementCommands.AddSettledFeeToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.FeeCalculatedDateTime, domainEvent.CalculatedValue, domainEvent.TransactionId, domainEvent.FeeId);
3951

40-
return await this.Mediator.Send(command, cancellationToken);
41-
}, retryPolicy, "MerchantSettlementDomainEventHandler - MerchantFeeSettledEvent");
52+
return await this.Mediator.Send(command, cancellationToken);
4253
}
4354
}

TransactionProcessor.BusinessLogic/EventHandling/MerchantStatementDomainEventHandler.cs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
using MediatR;
1+
using System;
2+
using MediatR;
23
using Polly;
34
using Shared.DomainDrivenDesign.EventSourcing;
45
using Shared.EventStore.EventHandling;
56
using SimpleResults;
7+
using System.Diagnostics;
68
using System.Threading;
79
using System.Threading.Tasks;
10+
using Prometheus;
811
using TransactionProcessor.BusinessLogic.Common;
912
using TransactionProcessor.BusinessLogic.Requests;
13+
using TransactionProcessor.BusinessLogic.Services;
1014
using TransactionProcessor.DomainEvents;
1115

1216
namespace TransactionProcessor.BusinessLogic.EventHandling
@@ -41,7 +45,26 @@ public MerchantStatementDomainEventHandler(IMediator mediator)
4145
public async Task<Result> Handle(IDomainEvent domainEvent,
4246
CancellationToken cancellationToken)
4347
{
44-
return await this.HandleSpecificDomainEvent((dynamic)domainEvent, cancellationToken);
48+
Stopwatch sw = Stopwatch.StartNew();
49+
String g = domainEvent.GetType().Name;
50+
String m = this.GetType().Name;
51+
Counter counterCalls = AggregateService.GetCounterMetric($"{m}_{g}_events_processed");
52+
Histogram histogramMetric = AggregateService.GetHistogramMetric($"{m}_{g}");
53+
counterCalls.Inc();
54+
55+
Task<Result> t = domainEvent switch
56+
{
57+
MerchantStatementDomainEvents.StatementGeneratedEvent de => this.HandleSpecificDomainEvent(de, cancellationToken),
58+
TransactionDomainEvents.TransactionHasBeenCompletedEvent de => this.HandleSpecificDomainEvent(de, cancellationToken),
59+
_ => null
60+
};
61+
62+
Result result = Result.Success();
63+
if (t != null)
64+
result = await t;
65+
sw.Stop();
66+
histogramMetric.Observe(sw.Elapsed.TotalSeconds);
67+
return result;
4568
}
4669

4770
/// <summary>
@@ -51,25 +74,16 @@ public async Task<Result> Handle(IDomainEvent domainEvent,
5174
/// <param name="cancellationToken">The cancellation token.</param>
5275
private async Task<Result> HandleSpecificDomainEvent(MerchantStatementDomainEvents.StatementGeneratedEvent domainEvent,
5376
CancellationToken cancellationToken) {
77+
MerchantStatementCommands.EmailMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.MerchantStatementId);
5478

55-
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(policyTag: "MerchantStatementDomainEventHandler - StatementGeneratedEvent");
56-
57-
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
58-
MerchantStatementCommands.EmailMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.MerchantStatementId);
59-
60-
return await this.Mediator.Send(command, cancellationToken);
61-
}, retryPolicy, "MerchantStatementDomainEventHandler - StatementGeneratedEvent");
79+
return await this.Mediator.Send(command, cancellationToken);
6280
}
6381

6482
private async Task<Result> HandleSpecificDomainEvent(TransactionDomainEvents.TransactionHasBeenCompletedEvent domainEvent,
6583
CancellationToken cancellationToken) {
66-
IAsyncPolicy<Result> retryPolicy = PolicyFactory.CreatePolicy(policyTag: "MerchantStatementDomainEventHandler - TransactionHasBeenCompletedEvent");
67-
68-
return await PolicyFactory.ExecuteWithPolicyAsync(async () => {
69-
MerchantStatementCommands.AddTransactionToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.CompletedDateTime, domainEvent.TransactionAmount, domainEvent.IsAuthorised, domainEvent.TransactionId);
84+
MerchantStatementCommands.AddTransactionToMerchantStatementCommand command = new(domainEvent.EstateId, domainEvent.MerchantId, domainEvent.CompletedDateTime, domainEvent.TransactionAmount, domainEvent.IsAuthorised, domainEvent.TransactionId);
7085

71-
return await this.Mediator.Send(command, cancellationToken);
72-
},retryPolicy, "MerchantStatementDomainEventHandler - TransactionHasBeenCompletedEvent");
86+
return await this.Mediator.Send(command, cancellationToken);
7387
}
7488

7589
#endregion

0 commit comments

Comments
 (0)