From 44ae98fbbaca3c753e90947c88dda75367e422ad Mon Sep 17 00:00:00 2001 From: Henrique Graca <999396+hjgraca@users.noreply.github.com> Date: Mon, 20 May 2024 11:21:30 +0100 Subject: [PATCH 1/2] add thread safety test. AddMetric lock. --- .../AWS.Lambda.Powertools.Metrics/Metrics.cs | 26 ++++++++++++------- .../Handlers/FunctionHandler.cs | 15 +++++++++++ .../Handlers/FunctionHandlerTests.cs | 12 +++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs index af72bd89..51b86e37 100644 --- a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs +++ b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs @@ -52,6 +52,11 @@ public class Metrics : IMetrics, IDisposable /// private readonly bool _captureColdStartEnabled; + // + // Shared synchronization object + // + private readonly object _lockObj = new(); + /// /// Creates a Metrics object that provides features to send metrics to Amazon Cloudwatch using the Embedded metric /// format (EMF). See @@ -98,17 +103,20 @@ void IMetrics.AddMetric(string key, double value, MetricUnit unit, MetricResolut "'AddMetric' method requires a valid metrics value. Value must be >= 0.", nameof(value)); } - var metrics = _context.GetMetrics(); - - if (metrics.Count > 0 && - (metrics.Count == PowertoolsConfigurations.MaxMetrics || - metrics.FirstOrDefault(x => x.Name == key) - ?.Values.Count == PowertoolsConfigurations.MaxMetrics)) + lock (_lockObj) { - _instance.Flush(true); + var metrics = _context.GetMetrics(); + + if (metrics.Count > 0 && + (metrics.Count == PowertoolsConfigurations.MaxMetrics || + metrics.FirstOrDefault(x => x.Name == key) + ?.Values.Count == PowertoolsConfigurations.MaxMetrics)) + { + _instance.Flush(true); + } + + _context.AddMetric(key, value, unit, metricResolution); } - - _context.AddMetric(key, value, unit, metricResolution); } /// diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs index 50bb050f..c781731d 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs @@ -13,8 +13,11 @@ * permissions and limitations under the License. */ +using System; using System.Globalization; +using System.Linq; using System.Threading.Tasks; +using AWS.Lambda.Powertools.Common; namespace AWS.Lambda.Powertools.Metrics.Tests.Handlers; @@ -41,4 +44,16 @@ public async Task HandleTestSecondCall(string input) return input.ToUpper(CultureInfo.InvariantCulture); } + + [Metrics(Namespace = "ns", Service = "svc")] + public async Task HandleMultipleThreads(string input) + { + await Parallel.ForEachAsync(Enumerable.Range(0, Environment.ProcessorCount * 2), async (x, _) => + { + Metrics.AddMetric("MyMetric", 1); + await Task.Delay(1); + }); + + return input.ToUpper(CultureInfo.InvariantCulture); + } } \ No newline at end of file diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandlerTests.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandlerTests.cs index 9531e3c9..4afba753 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandlerTests.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandlerTests.cs @@ -49,4 +49,16 @@ public async Task When_Metrics_Add_Metadata_Second_Invocation_Should_Not_Throw_E exception = await Record.ExceptionAsync( () => handler.HandleTestSecondCall("whatever")); Assert.Null(exception); } + + [Fact] + public async Task When_Metrics_Add_Metadata_FromMultipleThread_Should_Not_Throw_Exception() + { + // Arrange + Metrics.ResetForTest(); + var handler = new FunctionHandler(); + + // Act + var exception = await Record.ExceptionAsync(() => handler.HandleMultipleThreads("whatever")); + Assert.Null(exception); + } } \ No newline at end of file From ab95e85e61cbf8ed934e78dc56122dadb18af3e9 Mon Sep 17 00:00:00 2001 From: Henrique Graca <999396+hjgraca@users.noreply.github.com> Date: Mon, 20 May 2024 11:33:46 +0100 Subject: [PATCH 2/2] remove unused --- .../Handlers/FunctionHandler.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs index c781731d..271b2e21 100644 --- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs +++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs @@ -17,7 +17,6 @@ using System.Globalization; using System.Linq; using System.Threading.Tasks; -using AWS.Lambda.Powertools.Common; namespace AWS.Lambda.Powertools.Metrics.Tests.Handlers;