From 0dc6442986fc05aac90715182d4cc6cb7ee24d8d Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 19 Dec 2025 09:35:35 -0600 Subject: [PATCH] Fix CancellationTokenSource resource leaks (BLOCKER severity) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ManagedHttpDispatcher: Dispose quickFailCts and linkedTokenSource in finally block - CommandExecutor: Dispose _cancellationTokenSource on shutdown - Scheduler: Dispose _cancellationTokenSource on shutdown - IntegrationTestBase: Store CTS as field and dispose in TearDown 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../Http/Dispatchers/ManagedHttpDispatcher.cs | 8 ++++++-- src/NzbDrone.Core/Jobs/Scheduler.cs | 1 + .../Messaging/Commands/CommandExecutor.cs | 1 + src/NzbDrone.Integration.Test/IntegrationTestBase.cs | 11 +++++++++-- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs index 2847789197..345a8c9411 100644 --- a/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs +++ b/src/NzbDrone.Common/Http/Dispatchers/ManagedHttpDispatcher.cs @@ -280,6 +280,8 @@ private async ValueTask onConnect(SocketsHttpConnectionContext context, // This issue is being tracked at https://github.com/dotnet/runtime/issues/26177 and expected to be fixed in .NET 6. if (useIPv6) { + CancellationTokenSource quickFailCts = null; + CancellationTokenSource linkedTokenSource = null; try { var localToken = cancellationToken; @@ -287,8 +289,8 @@ private async ValueTask onConnect(SocketsHttpConnectionContext context, if (!hasResolvedIPv6Availability) { // to make things move fast, use a very low timeout for the initial ipv6 attempt. - var quickFailCts = new CancellationTokenSource(connection_establish_timeout); - var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, quickFailCts.Token); + quickFailCts = new CancellationTokenSource(connection_establish_timeout); + linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, quickFailCts.Token); localToken = linkedTokenSource.Token; } @@ -305,6 +307,8 @@ private async ValueTask onConnect(SocketsHttpConnectionContext context, finally { hasResolvedIPv6Availability = true; + linkedTokenSource?.Dispose(); + quickFailCts?.Dispose(); } } diff --git a/src/NzbDrone.Core/Jobs/Scheduler.cs b/src/NzbDrone.Core/Jobs/Scheduler.cs index 54e243467a..ccf46015ae 100644 --- a/src/NzbDrone.Core/Jobs/Scheduler.cs +++ b/src/NzbDrone.Core/Jobs/Scheduler.cs @@ -65,6 +65,7 @@ public void Handle(ApplicationShutdownRequested message) { _logger.Info("Shutting down scheduler"); _cancellationTokenSource.Cancel(true); + _cancellationTokenSource.Dispose(); Timer.Stop(); } } diff --git a/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs b/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs index 9a6f01edc5..d8dc0409bf 100644 --- a/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs +++ b/src/NzbDrone.Core/Messaging/Commands/CommandExecutor.cs @@ -147,6 +147,7 @@ public void Handle(ApplicationShutdownRequested message) { _logger.Info("Shutting down task execution"); _cancellationTokenSource.Cancel(true); + _cancellationTokenSource.Dispose(); } } } diff --git a/src/NzbDrone.Integration.Test/IntegrationTestBase.cs b/src/NzbDrone.Integration.Test/IntegrationTestBase.cs index 48913fedde..33ffe27fe5 100644 --- a/src/NzbDrone.Integration.Test/IntegrationTestBase.cs +++ b/src/NzbDrone.Integration.Test/IntegrationTestBase.cs @@ -60,6 +60,7 @@ public abstract class IntegrationTestBase private List _signalRReceived; private HubConnection _signalrConnection; + private CancellationTokenSource _signalrCts; protected IEnumerable SignalRMessages => _signalRReceived; @@ -148,6 +149,12 @@ public async Task IntegrationTearDown() _signalRReceived = new List(); } + if (_signalrCts != null) + { + _signalrCts.Dispose(); + _signalrCts = null; + } + if (Directory.Exists(TempDirectory)) { try @@ -174,11 +181,11 @@ protected async Task ConnectSignalR() _signalRReceived = new List(); _signalrConnection = new HubConnectionBuilder().WithUrl("http://localhost:7878/signalr/messages").Build(); - var cts = new CancellationTokenSource(); + _signalrCts = new CancellationTokenSource(); _signalrConnection.Closed += e => { - cts.Cancel(); + _signalrCts.Cancel(); return Task.CompletedTask; };