diff --git a/.github/workflows/install-dependencies/action.yml b/.github/workflows/install-dependencies/action.yml
index 80fea7da5..cc3e300fe 100644
--- a/.github/workflows/install-dependencies/action.yml
+++ b/.github/workflows/install-dependencies/action.yml
@@ -19,7 +19,7 @@ runs:
- name: Rustup
if: "${{ inputs.rust == 'true' }}"
shell: bash
- run: rustup default 1.67.1
+ run: rustup default 1.69.0
# - name: Cargo make
# if: "${{ inputs.rust == 'true' }}"
diff --git a/src/Elastic.Apm/Model/Transaction.cs b/src/Elastic.Apm/Model/Transaction.cs
index 7421091ea..659f24c6b 100644
--- a/src/Elastic.Apm/Model/Transaction.cs
+++ b/src/Elastic.Apm/Model/Transaction.cs
@@ -357,7 +357,7 @@ private void CheckAndCaptureBaggage()
///
/// Internal dictionary to keep track of and look up dropped span stats.
///
- private Dictionary _droppedSpanStatsMap;
+ private ConcurrentDictionary _droppedSpanStatsMap;
private bool _isEnded;
@@ -552,38 +552,35 @@ private Activity StartActivity(bool shouldRestartTrace)
return activity;
}
+ private readonly object _lock = new();
internal void UpdateDroppedSpanStats(string serviceTargetType, string serviceTargetName, string destinationServiceResource, Outcome outcome,
double duration
)
{
+ //lock the lazy initialization of the dictionary
if (_droppedSpanStatsMap == null)
{
- _droppedSpanStatsMap = new Dictionary
- {
- {
- new DroppedSpanStatsKey(serviceTargetType, serviceTargetName, outcome),
- new DroppedSpanStats(serviceTargetType, serviceTargetName, destinationServiceResource, outcome, duration)
- }
- };
+ lock (_lock)
+ _droppedSpanStatsMap ??= new ConcurrentDictionary();
}
- else
+
+ lock (_lock)
{
if (_droppedSpanStatsMap.Count >= 128)
return;
-
- if (_droppedSpanStatsMap.TryGetValue(new DroppedSpanStatsKey(serviceTargetType, serviceTargetName, outcome), out var item))
- {
- item.Duration ??=
- new DroppedSpanStats.DroppedSpanDuration { Sum = new DroppedSpanStats.DroppedSpanDuration.DroppedSpanDurationSum() };
-
- item.Duration.Count++;
- item.Duration.Sum.UsRaw += duration;
- }
- else
- {
- _droppedSpanStatsMap.Add(new DroppedSpanStatsKey(serviceTargetType, serviceTargetName, outcome),
- new DroppedSpanStats(serviceTargetType, serviceTargetName, destinationServiceResource, outcome, duration));
- }
+ //AddOrUpdate callbacks can run multiple times so still wrapping this in a lock
+ var key = new DroppedSpanStatsKey(serviceTargetType, serviceTargetName, outcome);
+ _droppedSpanStatsMap.AddOrUpdate(key,
+ _ => new DroppedSpanStats(serviceTargetType, serviceTargetName, destinationServiceResource, outcome, duration),
+ (_, stats) =>
+ {
+ stats.Duration ??=
+ new DroppedSpanStats.DroppedSpanDuration { Sum = new DroppedSpanStats.DroppedSpanDuration.DroppedSpanDurationSum() };
+
+ stats.Duration.Count++;
+ stats.Duration.Sum.UsRaw += duration;
+ return stats;
+ });
}
}