Skip to content

Commit 30045c7

Browse files
committed
Try to restructure RuntimeMetricsWriter for .NET Framework
1 parent 8603e6d commit 30045c7

File tree

1 file changed

+34
-2
lines changed

1 file changed

+34
-2
lines changed

tracer/src/Datadog.Trace/RuntimeMetrics/RuntimeMetricsWriter.cs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Runtime.CompilerServices;
1010
using System.Runtime.ExceptionServices;
1111
using System.Threading;
12+
using System.Threading.Tasks;
1213
using Datadog.Trace.Logging;
1314
using Datadog.Trace.Vendors.StatsdClient;
1415

@@ -39,8 +40,11 @@ internal class RuntimeMetricsWriter : IDisposable
3940

4041
private readonly TimeSpan _delay;
4142

43+
#if NETFRAMEWORK
44+
private readonly Task _pushEventsTask;
45+
#else
4246
private readonly Timer _timer;
43-
47+
#endif
4448
private readonly IRuntimeMetricsListener _listener;
4549

4650
private readonly bool _enableProcessMetrics;
@@ -120,7 +124,11 @@ internal RuntimeMetricsWriter(IDogStatsd statsd, TimeSpan delay, bool inAzureApp
120124
Log.Warning(ex, "Unable to initialize runtime listener, some runtime metrics will be missing");
121125
}
122126

127+
#if NETFRAMEWORK
128+
_pushEventsTask = Task.Factory.StartNew(PushEvents, TaskCreationOptions.LongRunning);
129+
#else
123130
_timer = new Timer(_ => PushEvents(), null, delay, Timeout.InfiniteTimeSpan);
131+
#endif
124132
}
125133

126134
/// <summary>
@@ -137,6 +145,12 @@ public void Dispose()
137145
}
138146

139147
Log.Debug("Disposing Runtime Metrics timer");
148+
#if NETFRAMEWORK
149+
if (_pushEventsTask.Wait(TimeSpan.FromMilliseconds(5_000)))
150+
{
151+
Log.Warning("Failed to dispose Runtime Metrics timer after 5 seconds");
152+
}
153+
#else
140154
// Callbacks can occur after the Dispose() method overload has been called,
141155
// because the timer queues callbacks for execution by thread pool threads.
142156
// Using the Dispose(WaitHandle) method overload to waits until all callbacks have completed.
@@ -148,7 +162,7 @@ public void Dispose()
148162
Log.Warning("Failed to dispose Runtime Metrics timer after 5 seconds");
149163
}
150164
}
151-
165+
#endif
152166
Log.Debug("Disposing other resources for Runtime Metrics");
153167
AppDomain.CurrentDomain.FirstChanceException -= FirstChanceException;
154168
// We don't dispose runtime metrics on .NET Core because of https://github.com/dotnet/runtime/issues/103480
@@ -256,6 +270,23 @@ internal void PushEvents()
256270
{
257271
var callbackExecutionDuration = DateTime.UtcNow - now;
258272

273+
#if NETFRAMEWORK
274+
// Ideally we'd wait for the full time, but we need to make sure we shutdown in a relatively timely fashion
275+
const int loopDurationMs = 200;
276+
var newDelay = (int)(_delay - callbackExecutionDuration).TotalMilliseconds;
277+
278+
// Missed it, so just reset
279+
if (newDelay <= 0)
280+
{
281+
newDelay = (int)_delay.TotalMilliseconds;
282+
}
283+
284+
while (newDelay > 0 && Volatile.Read(ref _disposed) == 0)
285+
{
286+
Thread.Sleep(Math.Min(newDelay, loopDurationMs));
287+
newDelay -= loopDurationMs;
288+
}
289+
#else
259290
var newDelay = _delay - callbackExecutionDuration;
260291

261292
if (newDelay < TimeSpan.Zero)
@@ -270,6 +301,7 @@ internal void PushEvents()
270301
catch (ObjectDisposedException)
271302
{
272303
}
304+
#endif
273305
}
274306
}
275307

0 commit comments

Comments
 (0)