From db8e0a4a766e14f1239e04bed7092d75e28562df Mon Sep 17 00:00:00 2001 From: klettier Date: Sat, 8 Nov 2025 18:56:49 +0100 Subject: [PATCH] Catch all exceptions in HeartbeatWriteTimerCallback and HeartbeatReadTimerCallback to avoid crash --- .../Impl/Connection.Heartbeat.cs | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/projects/RabbitMQ.Client/Impl/Connection.Heartbeat.cs b/projects/RabbitMQ.Client/Impl/Connection.Heartbeat.cs index 5e82d2b2c..d189b0187 100644 --- a/projects/RabbitMQ.Client/Impl/Connection.Heartbeat.cs +++ b/projects/RabbitMQ.Client/Impl/Connection.Heartbeat.cs @@ -80,17 +80,19 @@ private void NotifyHeartbeatListener() _heartbeatDetected = true; } + // Intentionally declared `async void` because `System.Threading.Timer` requires a void callback. + // Catch all exceptions in it: any exceptions unhandled by the method might lead to the process crash private async void HeartbeatReadTimerCallback(object? state) { - if (_heartbeatReadTimer is null) + try { - return; - } + if (_heartbeatReadTimer is null) + { + return; + } - bool shouldTerminate = false; + bool shouldTerminate = false; - try - { if (false == _closed) { if (_heartbeatDetected) @@ -131,34 +133,29 @@ await FinishCloseAsync(cts.Token) _heartbeatReadTimer?.Change((int)Heartbeat.TotalMilliseconds, Timeout.Infinite); } } - catch (OperationCanceledException) - { - if (false == _mainLoopCts.IsCancellationRequested) - { - throw; - } - } catch (ObjectDisposedException) { // timer is already disposed, // e.g. due to shutdown } - catch (NullReferenceException) + catch (Exception) { - // timer has already been disposed from a different thread after null check - // this event should be rare + // ignore + // peer unavailability. See rabbitmq/rabbitmq-dotnet-client#638 for details. } } + // Intentionally declared `async void` because `System.Threading.Timer` requires a void callback. + // Catch all exceptions in it: any exceptions unhandled by the method might lead to the process crash private async void HeartbeatWriteTimerCallback(object? state) { - if (_heartbeatWriteTimer is null) - { - return; - } - try { + if (_heartbeatWriteTimer is null) + { + return; + } + if (false == _closed) { await WriteAsync(Client.Impl.Framing.Heartbeat.GetHeartbeatFrame(), _mainLoopCts.Token)