From e636f12459ced0ca91285f45127a4167efb7380f Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 4 Feb 2019 09:03:54 +0100 Subject: [PATCH] Fix leak in BackgroundTaskRunner --- .../Scheduling/BackgroundTaskRunner.cs | 48 ++++++++++++------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs b/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs index d9e3c3c980..47e97593f0 100644 --- a/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs +++ b/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs @@ -355,6 +355,8 @@ namespace Umbraco.Web.Scheduling // break latched tasks // stop processing the queue _shutdownTokenSource.Cancel(false); // false is the default + _shutdownTokenSource.Dispose(); + _shutdownTokenSource = null; } // tasks in the queue will be executed... @@ -379,28 +381,38 @@ namespace Umbraco.Web.Scheduling _cancelTokenSource = CancellationTokenSource.CreateLinkedTokenSource(_shutdownToken); } - // wait for latch should return the task - // if it returns null it's either that the task has been cancelled - // or the whole runner is going down - in both cases, continue, - // and GetNextBackgroundTask will take care of shutdowns - bgTask = await WaitForLatch(bgTask, _cancelTokenSource.Token); - if (bgTask == null) continue; - - // executes & be safe - RunAsync should NOT throw but only raise an event, - // but... just make sure we never ever take everything down try { - await RunAsync(bgTask, _cancelTokenSource.Token).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.Error(ex, "{LogPrefix} Task runner exception", _logPrefix); - } + // wait for latch should return the task + // if it returns null it's either that the task has been cancelled + // or the whole runner is going down - in both cases, continue, + // and GetNextBackgroundTask will take care of shutdowns + bgTask = await WaitForLatch(bgTask, _cancelTokenSource.Token); - // done - lock (_locker) + if (bgTask != null) + { + // executes & be safe - RunAsync should NOT throw but only raise an event, + // but... just make sure we never ever take everything down + try + { + await RunAsync(bgTask, _cancelTokenSource.Token).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.Error(ex, "{LogPrefix} Task runner exception", _logPrefix); + } + } + } + finally { - _cancelTokenSource = null; + // done + lock (_locker) + { + // always dispose CancellationTokenSource when you are done using them + // https://lowleveldesign.org/2015/11/30/catch-in-cancellationtokensource/ + _cancelTokenSource.Dispose(); + _cancelTokenSource = null; + } } } }