oracle / oracle/dotnet-db-samples
Exception when concurrently getting Metrics
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 434
- Forks
- 191
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 1
Description
When MeterListener.RecordObservableInstruments() is called concurrently from multiple threads, an Exception is thrown.
ArgumentException: An item with the same key has already been added. Key: OracleMetricsRepro[23212,1]
at System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException[T](T key)
at System.Collections.Generic.Dictionary`2.TryInsert(TKey key, TValue value, InsertionBehavior behavior)
at System.Collections.Generic.Dictionary`2.Add(TKey key, TValue value)
at Oracle.ManagedDataAccess.Client.OracleMetricsCollection.GetNumberOfActiveConnections()
at Oracle.ManagedDataAccess.Client.OracleMetricsInstrument.GetMeasurements()
at System.Diagnostics.Metrics.ObservableInstrument`1.Observe(Object callback)
at System.Diagnostics.Metrics.ObservableGauge`1.Observe()
at System.Diagnostics.Metrics.ObservableInstrument`1.Observe(MeterListener listener)
at System.Diagnostics.Metrics.MeterListener.RecordObservableInstruments()
This behavior can be reproduced with this simple program (might need to be started multiple times, it doesn't happen every time):
using Oracle.ManagedDataAccess.Client;
using System.Diagnostics.Metrics;
internal class Program
{
private static MeterListener listener;
public static async Task Main(string[] args)
{
listener = new MeterListener();
listener.SetMeasurementEventCallback<long>((inst, value, tags, state) =>
{
Console.WriteLine(value);
});
listener.InstrumentPublished = (instrument, l) =>
{
if (instrument.Meter.Name == "Oracle.ManagedDataAccess.Core" &&
instrument.Name == "odp.number_of_active_connections")
{
l.EnableMeasurementEvents(instrument);
}
};
listener.Start();
var conn = new OracleConnection("TODO");
await conn.OpenAsync(); // open connection so that metrics are available
await Task.WhenAll(DummyAsync(), DummyAsync());
}
public static async Task DummyAsync()
{
await Task.Delay(10); // add delay so that RecordObservableInstruments is not called syncronously
listener.RecordObservableInstruments(); // make ODP.NET emit the metric value
}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reproduction program and the stack trace through MeterListener.RecordObservableInstruments(), OracleMetricsInstrument.GetMeasurements(), and OracleMetricsCollection.GetNumberOfActiveConnections(). Run two concurrent calls after opening an OracleConnection to reproduce the failure. Done means concurrent metric collection no longer throws the duplicate-key exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100