From 3e2371f359773b2bb1efcc7b0c89c922e5144cb8 Mon Sep 17 00:00:00 2001 From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com> Date: Tue, 6 May 2025 14:28:44 +0200 Subject: [PATCH 1/2] Replace reflection-based Task.Result with Task.GetAwaiter.GetResult() --- src/Common/src/Common/DynamicTypeAccess/TaskShim.cs | 10 ++++++++-- .../DynamicTypeAccess/MongoClientInterfaceShim.cs | 2 +- .../ConnectionFactoryInterfaceShim.cs | 3 ++- .../DynamicTypeAccess/ConnectionMultiplexerShim.cs | 3 ++- .../Redis/DynamicTypeAccess/DatabaseInterfaceShim.cs | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Common/src/Common/DynamicTypeAccess/TaskShim.cs b/src/Common/src/Common/DynamicTypeAccess/TaskShim.cs index e1faf8163d..561bf2fd96 100644 --- a/src/Common/src/Common/DynamicTypeAccess/TaskShim.cs +++ b/src/Common/src/Common/DynamicTypeAccess/TaskShim.cs @@ -16,8 +16,6 @@ internal sealed class TaskShim(object instance) { public override Task Instance => (Task)base.Instance; - public TResult Result => InstanceAccessor.GetPropertyValue("Result"); - private static InstanceAccessor Wrap(object instance) { Type taskLikeType = instance.GetType(); @@ -25,6 +23,14 @@ private static InstanceAccessor Wrap(object instance) return new InstanceAccessor(typeAccessor, instance); } + public TResult GetResult() + { + object awaiter = InstanceAccessor.InvokeMethod("GetAwaiter", true)!; + var awaiterAccessor = new InstanceAccessor(new TypeAccessor(awaiter.GetType()), awaiter); + object result = awaiterAccessor.InvokeMethod("GetResult", true)!; + return (TResult)result; + } + public void Dispose() { Instance.Dispose(); diff --git a/src/Connectors/src/Connectors/MongoDb/DynamicTypeAccess/MongoClientInterfaceShim.cs b/src/Connectors/src/Connectors/MongoDb/DynamicTypeAccess/MongoClientInterfaceShim.cs index 717ba6491b..be829fe4a2 100644 --- a/src/Connectors/src/Connectors/MongoDb/DynamicTypeAccess/MongoClientInterfaceShim.cs +++ b/src/Connectors/src/Connectors/MongoDb/DynamicTypeAccess/MongoClientInterfaceShim.cs @@ -16,6 +16,6 @@ public async Task ListDatabaseNamesAsync(CancellationToken cancella await task; using var taskShim = new TaskShim(task); - return taskShim.Result; + return taskShim.GetResult(); } } diff --git a/src/Connectors/src/Connectors/RabbitMQ/DynamicTypeAccess/ConnectionFactoryInterfaceShim.cs b/src/Connectors/src/Connectors/RabbitMQ/DynamicTypeAccess/ConnectionFactoryInterfaceShim.cs index 9a063c248a..e43ba3260e 100644 --- a/src/Connectors/src/Connectors/RabbitMQ/DynamicTypeAccess/ConnectionFactoryInterfaceShim.cs +++ b/src/Connectors/src/Connectors/RabbitMQ/DynamicTypeAccess/ConnectionFactoryInterfaceShim.cs @@ -18,6 +18,7 @@ public async Task CreateConnectionAsync(CancellationTok await task; using var taskShim = new TaskShim(task); - return new ConnectionInterfaceShim(_packageResolver, taskShim.Result); + IDisposable connection = taskShim.GetResult(); + return new ConnectionInterfaceShim(_packageResolver, connection); } } diff --git a/src/Connectors/src/Connectors/Redis/DynamicTypeAccess/ConnectionMultiplexerShim.cs b/src/Connectors/src/Connectors/Redis/DynamicTypeAccess/ConnectionMultiplexerShim.cs index 5fe2106a50..5f840f4946 100644 --- a/src/Connectors/src/Connectors/Redis/DynamicTypeAccess/ConnectionMultiplexerShim.cs +++ b/src/Connectors/src/Connectors/Redis/DynamicTypeAccess/ConnectionMultiplexerShim.cs @@ -35,7 +35,8 @@ public static async Task ConnectAsync(StackE await task; using var taskShim = new TaskShim(task); - return new ConnectionMultiplexerInterfaceShim(packageResolver, taskShim.Result); + IDisposable connectionMultiplexer = taskShim.GetResult(); + return new ConnectionMultiplexerInterfaceShim(packageResolver, connectionMultiplexer); } public void Dispose() diff --git a/src/Connectors/src/Connectors/Redis/DynamicTypeAccess/DatabaseInterfaceShim.cs b/src/Connectors/src/Connectors/Redis/DynamicTypeAccess/DatabaseInterfaceShim.cs index 7d4868d8f1..be782b2f29 100644 --- a/src/Connectors/src/Connectors/Redis/DynamicTypeAccess/DatabaseInterfaceShim.cs +++ b/src/Connectors/src/Connectors/Redis/DynamicTypeAccess/DatabaseInterfaceShim.cs @@ -17,6 +17,6 @@ public async Task PingAsync() await task; using var taskShim = new TaskShim(task); - return taskShim.Result; + return taskShim.GetResult(); } } From 6a85fe8ae29d05d6b6f12f2d9eb31fdb5a6963f9 Mon Sep 17 00:00:00 2001 From: Bart Koelman <104792814+bart-vmware@users.noreply.github.com> Date: Tue, 6 May 2025 15:08:48 +0200 Subject: [PATCH 2/2] Fix timer leak in EventPipeThreadDumper --- .../ThreadDump/EventPipeThreadDumper.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs b/src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs index 287c269e6b..0412f1d8af 100644 --- a/src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs +++ b/src/Management/src/Endpoint/Actuators/ThreadDump/EventPipeThreadDumper.cs @@ -424,12 +424,23 @@ private async Task CreateTraceFileAsync(EventPipeSession session, Cancel cancellationToken.ThrowIfCancellationRequested(); // check if rundown is taking more than 5 seconds and log - Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(5), cancellationToken); + using var timeoutSource = new CancellationTokenSource(); + Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(5), timeoutSource.Token); + Task completedTask = await Task.WhenAny(copyTask, timeoutTask); - if (completedTask == timeoutTask && !cancellationToken.IsCancellationRequested) + if (completedTask == timeoutTask) + { + if (!cancellationToken.IsCancellationRequested) + { + _logger.LogInformation("Sufficiently large applications can cause this command to take non-trivial amounts of time."); + } + } + else { - _logger.LogInformation("Sufficiently large applications can cause this command to take non-trivial amounts of time."); + // Cancel the internal timer allocated inside Task.Delay, so that it does not fire and its resources are released. + // See https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#using-a-timeout. + await timeoutSource.CancelAsync(); } await copyTask;