diff --git a/src/Particular.LicensingComponent.UnitTests/ApprovalFiles/ThroughputCollector_Report_Throughput_Tests.Should_generate_correct_report.approved.txt b/src/Particular.LicensingComponent.UnitTests/ApprovalFiles/ThroughputCollector_Report_Throughput_Tests.Should_generate_correct_report.approved.txt index df4c5ac553..56f72cf300 100644 --- a/src/Particular.LicensingComponent.UnitTests/ApprovalFiles/ThroughputCollector_Report_Throughput_Tests.Should_generate_correct_report.approved.txt +++ b/src/Particular.LicensingComponent.UnitTests/ApprovalFiles/ThroughputCollector_Report_Throughput_Tests.Should_generate_correct_report.approved.txt @@ -141,7 +141,7 @@ "DailyThroughputFromMonitoring": [] } ], - "TotalThroughput": 249, + "TotalThroughput": 238, "TotalQueues": 5, "IgnoredQueues": [], "EnvironmentInformation": { diff --git a/src/Particular.LicensingComponent.UnitTests/ThroughputCollector/ThroughputCollector_Report_Throughput_Tests.cs b/src/Particular.LicensingComponent.UnitTests/ThroughputCollector/ThroughputCollector_Report_Throughput_Tests.cs index 6603abcad0..28ca74affa 100644 --- a/src/Particular.LicensingComponent.UnitTests/ThroughputCollector/ThroughputCollector_Report_Throughput_Tests.cs +++ b/src/Particular.LicensingComponent.UnitTests/ThroughputCollector/ThroughputCollector_Report_Throughput_Tests.cs @@ -147,11 +147,37 @@ await DataStore.CreateBuilder() using (Assert.EnterMultipleScope()) { - Assert.That(report.ReportData.TotalThroughput, Is.EqualTo(195), $"Incorrect TotalThroughput recorded"); + Assert.That(report.ReportData.TotalThroughput, Is.EqualTo(185), $"Incorrect TotalThroughput recorded"); Assert.That(report.ReportData.TotalQueues, Is.EqualTo(3), $"Incorrect TotalQueues recorded"); } } + [Test] + public async Task Should_report_total_throughput_as_maximum_daily_throughput_across_all_endpoints() + { + // Arrange - endpoints peak on different days; TotalThroughput is the best single day + // of the organization-wide sum, not the sum of each endpoint's individual peak + var startDate = new DateOnly(2024, 4, 24); + + await DataStore.CreateBuilder() + .AddEndpoint("Endpoint1", sources: [ThroughputSource.Broker]).WithThroughput(startDate: startDate, data: [100, 10]) + .AddEndpoint("Endpoint2", sources: [ThroughputSource.Broker]).WithThroughput(startDate: startDate, data: [20, 100]) + .Build(); + + // Act + var report = await ThroughputCollector.GenerateThroughputReport("", null, default); + + // Assert + Assert.That(report, Is.Not.Null); + + using (Assert.EnterMultipleScope()) + { + Assert.That(report.ReportData.Queues.First(w => w.QueueName == "Endpoint1").Throughput, Is.EqualTo(100), $"Incorrect Throughput recorded for Endpoint1"); + Assert.That(report.ReportData.Queues.First(w => w.QueueName == "Endpoint2").Throughput, Is.EqualTo(100), $"Incorrect Throughput recorded for Endpoint2"); + Assert.That(report.ReportData.TotalThroughput, Is.EqualTo(120), $"TotalThroughput should be the maximum daily throughput across all endpoints, not the sum of each endpoint's maximum"); + } + } + [Test] public async Task Should_return_correct_throughput_in_report_when_multiple_sources() { diff --git a/src/Particular.LicensingComponent/ThroughputCollector.cs b/src/Particular.LicensingComponent/ThroughputCollector.cs index 925cc203c0..af4542d210 100644 --- a/src/Particular.LicensingComponent/ThroughputCollector.cs +++ b/src/Particular.LicensingComponent/ThroughputCollector.cs @@ -119,6 +119,7 @@ public async Task GenerateThroughputReport(string spVersion, DateT var queueThroughputs = new List(); List ignoredQueueNames = []; + var dailyThroughputTotals = new Dictionary(); await foreach (var endpointData in GetDistinctEndpointData(cancellationToken)) { @@ -140,6 +141,11 @@ public async Task GenerateThroughputReport(string spVersion, DateT }; queueThroughputs.Add(queueThroughput); + + foreach (var (date, messageCount) in endpointData.ThroughputData.DailyThroughput()) + { + dailyThroughputTotals[date] = dailyThroughputTotals.GetValueOrDefault(date) + messageCount; + } } var auditServiceMetadata = await dataStore.GetAuditServiceMetadata(cancellationToken); @@ -161,7 +167,8 @@ public async Task GenerateThroughputReport(string spVersion, DateT IgnoredQueues = [.. ignoredQueueNames], Queues = [.. queueThroughputs], TotalQueues = queueThroughputs.Count, - TotalThroughput = queueThroughputs.Sum(q => q.Throughput ?? 0), + //the maximum number of messages processed across all endpoints in a single day + TotalThroughput = dailyThroughputTotals.Count > 0 ? dailyThroughputTotals.Values.Max() : 0, EnvironmentInformation = new EnvironmentInformation { AuditServicesData = new AuditServicesData(auditServiceMetadata.Versions, auditServiceMetadata.Transports), EnvironmentData = brokerMetaData.Data } }; diff --git a/src/Particular.LicensingComponent/ThroughputDataExtensions.cs b/src/Particular.LicensingComponent/ThroughputDataExtensions.cs index 6d54edb6c9..cc0aced7ee 100644 --- a/src/Particular.LicensingComponent/ThroughputDataExtensions.cs +++ b/src/Particular.LicensingComponent/ThroughputDataExtensions.cs @@ -23,6 +23,13 @@ public static long MaxDailyThroughput(this List throughputs) return 0; } + // Daily throughput for an endpoint. When multiple sources have data for the same day, + // the maximum value is used, since all sources measure the same messages. + public static IEnumerable DailyThroughput(this List throughputs) => throughputs + .SelectMany(td => td) + .GroupBy(kvp => kvp.Key) + .Select(group => new EndpointDailyThroughput(group.Key, group.Max(kvp => kvp.Value))); + public static MonthlyThroughput[] MonthlyThroughput(this List throughputs) => [.. throughputs .SelectMany(data => data) .GroupBy(kvp => $"{kvp.Key:yyyy-MM}")