Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions src/Nethermind/Nethermind.Monitoring.Test/MetricsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using Nethermind.Core;
using Nethermind.Core.Attributes;
Expand Down Expand Up @@ -176,6 +178,45 @@ public void Register_and_update_metrics_should_not_throw_exception()
});
}

[Test]
public void UpdateAllMetrics_does_not_throw_when_registration_is_concurrent()
{
MetricsConfig metricsConfig = new() { Enabled = true };
MetricsController metricsController = new(metricsConfig);

using CancellationTokenSource cts = new(TimeSpan.FromSeconds(2));
CancellationToken ct = cts.Token;

// Continuously call UpdateAllMetrics on one thread while registering metrics on another
Task updater = Task.Run(() =>
{
while (!ct.IsCancellationRequested)
{
metricsController.UpdateAllMetrics();
}
});

Task registrar = Task.Run(() =>
{
Type[] types =
[
typeof(TestMetrics),
typeof(Blockchain.Metrics),
typeof(Evm.Metrics),
typeof(Network.Metrics),
typeof(Db.Metrics),
];

for (int i = 0; !ct.IsCancellationRequested; i++)
{
metricsController.RegisterMetrics(types[i % types.Length]);
metricsController.AddMetricsUpdateAction(() => { });
}
});

Assert.DoesNotThrowAsync(() => Task.WhenAll(updater, registrar));
}

[Test]
public void All_config_items_have_descriptions()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ public partial class MetricsController : IMetricsController
private static bool _staticLabelsInitialized;

private readonly Dictionary<Type, IMetricUpdater[]> _metricUpdaters = new();
private volatile IMetricUpdater[][] _updaterValues = [];

// Largely for testing reason
internal readonly Dictionary<string, IMetricUpdater> _individualUpdater = new();

private readonly bool _useCounters;
private readonly bool _enableDetailedMetric;

private readonly List<Action> _callbacks = new();
private volatile Action[] _callbacks = [];

public interface IMetricUpdater
{
Expand Down Expand Up @@ -235,6 +236,7 @@ public void RegisterMetrics(Type type)
}
}
_metricUpdaters[type] = metricUpdaters.ToArray();
_updaterValues = [.. _metricUpdaters.Values];
}
}

Expand Down Expand Up @@ -354,7 +356,7 @@ public void UpdateAllMetrics()
callback();
}

foreach (IMetricUpdater[] updaters in _metricUpdaters.Values)
foreach (IMetricUpdater[] updaters in _updaterValues)
{
foreach (IMetricUpdater metricUpdater in updaters)
{
Expand All @@ -363,7 +365,7 @@ public void UpdateAllMetrics()
}
}

public void AddMetricsUpdateAction(Action callback) => _callbacks.Add(callback);
public void AddMetricsUpdateAction(Action callback) => _callbacks = [.. _callbacks, callback];

private static string GetGaugeNameKey(params string[] par) => string.Join('.', par);

Expand Down