Skip to content

Commit

Permalink
fix Metric livelock by replacing potential infinate loop in MetricVal…
Browse files Browse the repository at this point in the history
…uesBuffer.GetAndResetValue (#2612)

* initial commit

* less invasive change

* rename

* review comment and changelog

* Update CHANGELOG.md

* update changelog

* log warning

* sort usings

* fxcop
  • Loading branch information
TimothyMothra authored Jun 17, 2022
1 parent f1ebc65 commit e9d4974
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,9 @@ public void IngestionResponseTimeEventCounter(float responseDurationInMs)
[Event(75, Message = "Ingestion Service responded with redirect. {0}", Level = EventLevel.Error)]
public void IngestionRedirectError(string message, string appDomainName = "Incorrect") => this.WriteEvent(75, message, this.nameProvider.Name);

[Event(76, Message = "MetricValueBuffer exceeded spin count.", Level = EventLevel.Warning)]
public void MetricValueBufferExceededSpinCount(string appDomainName = "Incorrect") => this.WriteEvent(76, this.nameProvider.Name);

[NonEvent]
public void TransmissionStatusEventFailed(Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Threading;
using System.Threading.Tasks;

using Microsoft.ApplicationInsights.Extensibility.Implementation.Tracing;

#pragma warning disable SA1649 // File name must match first type name
#pragma warning disable SA1402 // File may only contain a single class

Expand Down Expand Up @@ -91,13 +93,19 @@ public TValue GetAndResetValue(int index)
while (this.IsInvalidValue(value))
{
spinWait.SpinOnce();

if (spinWait.Count % 100 == 0)
{
// In tests (including stress tests) we always finished wating before 100 cycles.
// In tests (including stress tests) we always finished waiting before 100 cycles.
// However, this is a protection against en extreme case on a slow machine.
Task.Delay(10).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult();
}
else if (spinWait.Count > 10000)
{
// Exceeded maximum spin count. Break out to avoid infinite loop.
CoreEventSource.Log.MetricValueBufferExceededSpinCount();
break;
}

value = this.GetAndResetValueOnce(this.values, index);
}
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
- [Extension methods to retrive specific operation details.](https://github.com/microsoft/ApplicationInsights-dotnet/issues/1350)
- [Mark Instrumentation Key based APIs as Obsolete](https://github.com/microsoft/ApplicationInsights-dotnet/issues/2560).
- See also: https://docs.microsoft.com/azure/azure-monitor/app/migrate-from-instrumentation-keys-to-connection-strings
- [Fix: Livelock in MetricValuesBuffer.](https://github.com/microsoft/ApplicationInsights-dotnet/pull/2612)
Mitigation for TelemetryClient.Flush deadlocks ([#1186](https://github.com/microsoft/ApplicationInsights-dotnet/issues/1186))

## Version 2.21.0-beta1
- [Support IPv6 in request headers](https://github.com/microsoft/ApplicationInsights-dotnet/issues/2521)
Expand Down

0 comments on commit e9d4974

Please sign in to comment.