diff --git a/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs b/libraries/src/AWS.Lambda.Powertools.Metrics/Metrics.cs
index af72bd895..51b86e370 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 50bb050fa..271b2e21d 100644
--- a/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs
+++ b/libraries/tests/AWS.Lambda.Powertools.Metrics.Tests/Handlers/FunctionHandler.cs
@@ -13,7 +13,9 @@
* permissions and limitations under the License.
*/
+using System;
using System.Globalization;
+using System.Linq;
using System.Threading.Tasks;
namespace AWS.Lambda.Powertools.Metrics.Tests.Handlers;
@@ -41,4 +43,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 9531e3c92..4afba753b 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