Merge pull request #12153 from vsilvar/v9/bugfix/12022_recurring_hosted_service_scope_leak

Fixes RecurringHostServices leaking the execution context / ambient scope
This commit is contained in:
Nikolaj Geisle
2022-03-22 12:58:38 +01:00
committed by Nikolaj Geisle
parent 04c292f167
commit 0d836875c7
11 changed files with 32 additions and 12 deletions

View File

@@ -32,7 +32,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
IContentVersionService service,
IMainDom mainDom,
IServerRoleAccessor serverRoleAccessor)
: base(TimeSpan.FromHours(1), TimeSpan.FromMinutes(3))
: base(logger, TimeSpan.FromHours(1), TimeSpan.FromMinutes(1))
{
_runtimeState = runtimeState;
_logger = logger;

View File

@@ -61,6 +61,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
IProfilingLogger profilingLogger,
ICronTabParser cronTabParser)
: base(
logger,
healthChecksSettings.Value.Notification.Period,
healthChecksSettings.Value.GetNotificationDelay(cronTabParser, DateTime.Now, DefaultDelay))
{

View File

@@ -49,7 +49,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
IProfilingLogger profilingLogger,
IServerRoleAccessor serverRegistrar,
IHttpClientFactory httpClientFactory)
: base(TimeSpan.FromMinutes(5), DefaultDelay)
: base(logger, TimeSpan.FromMinutes(5), DefaultDelay)
{
_hostingEnvironment = hostingEnvironment;
_mainDom = mainDom;

View File

@@ -48,7 +48,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
IScopeProvider scopeProvider,
ILogger<LogScrubber> logger,
IProfilingLogger profilingLogger)
: base(TimeSpan.FromHours(4), DefaultDelay)
: base(logger, TimeSpan.FromHours(4), DefaultDelay)
{
_mainDom = mainDom;
_serverRegistrar = serverRegistrar;

View File

@@ -5,6 +5,7 @@ using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Umbraco.Cms.Infrastructure.HostedServices
{
@@ -21,6 +22,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
/// </summary>
protected static readonly TimeSpan DefaultDelay = TimeSpan.FromMinutes(3);
private readonly ILogger _logger;
private TimeSpan _period;
private readonly TimeSpan _delay;
private Timer _timer;
@@ -29,10 +31,12 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
/// <summary>
/// Initializes a new instance of the <see cref="RecurringHostedServiceBase"/> class.
/// </summary>
/// <param name="period">Timepsan representing how often the task should recur.</param>
/// <param name="delay">Timespan represeting the initial delay after application start-up before the first run of the task occurs.</param>
protected RecurringHostedServiceBase(TimeSpan period, TimeSpan delay)
/// <param name="logger">Logger.</param>
/// <param name="period">Timespan representing how often the task should recur.</param>
/// <param name="delay">Timespan representing the initial delay after application start-up before the first run of the task occurs.</param>
protected RecurringHostedServiceBase(ILogger logger, TimeSpan period, TimeSpan delay)
{
_logger = logger;
_period = period;
_delay = delay;
}
@@ -40,7 +44,11 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
/// <inheritdoc/>
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(ExecuteAsync, null, (int)_delay.TotalMilliseconds, (int)_period.TotalMilliseconds);
using (!ExecutionContext.IsFlowSuppressed() ? (IDisposable)ExecutionContext.SuppressFlow() : null)
{
_timer = new Timer(ExecuteAsync, null, (int)_delay.TotalMilliseconds, (int)_period.TotalMilliseconds);
}
return Task.CompletedTask;
}
@@ -61,6 +69,10 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
// Hat-tip: https://stackoverflow.com/a/14207615/489433
await PerformExecuteAsync(state);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled exception in recurring hosted service {serviceName}.", GetType().Name);
}
finally
{
// Resume now that the task is complete - Note we use period in both because we don't want to execute again after the delay.

View File

@@ -23,7 +23,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
public ReportSiteTask(
ILogger<ReportSiteTask> logger,
ITelemetryService telemetryService)
: base(TimeSpan.FromDays(1), TimeSpan.FromMinutes(1))
: base(logger, TimeSpan.FromDays(1), TimeSpan.FromMinutes(1))
{
_logger = logger;
_telemetryService = telemetryService;

View File

@@ -71,7 +71,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
ILogger<ScheduledPublishing> logger,
IServerMessenger serverMessenger,
IScopeProvider scopeProvider)
: base(TimeSpan.FromMinutes(1), DefaultDelay)
: base(logger, TimeSpan.FromMinutes(1), DefaultDelay)
{
_runtimeState = runtimeState;
_mainDom = mainDom;

View File

@@ -30,7 +30,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration
/// <param name="logger">The typed logger.</param>
/// <param name="globalSettings">The configuration for global settings.</param>
public InstructionProcessTask(IRuntimeState runtimeState, IServerMessenger messenger, ILogger<InstructionProcessTask> logger, IOptions<GlobalSettings> globalSettings)
: base(globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1))
: base(logger, globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1))
{
_runtimeState = runtimeState;
_messenger = messenger;

View File

@@ -44,7 +44,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration
ILogger<TouchServerTask> logger,
IOptions<GlobalSettings> globalSettings,
IServerRoleAccessor serverRoleAccessor)
: base(globalSettings.Value.DatabaseServerRegistrar.WaitTimeBetweenCalls, TimeSpan.FromSeconds(15))
: base(logger, globalSettings.Value.DatabaseServerRegistrar.WaitTimeBetweenCalls, TimeSpan.FromSeconds(15))
{
_runtimeState = runtimeState;
_serverRegistrationService = serverRegistrationService ?? throw new ArgumentNullException(nameof(serverRegistrationService));

View File

@@ -33,7 +33,7 @@ namespace Umbraco.Cms.Infrastructure.HostedServices
/// <param name="mainDom">Representation of the main application domain.</param>
/// <param name="logger">The typed logger.</param>
public TempFileCleanup(IIOHelper ioHelper, IMainDom mainDom, ILogger<TempFileCleanup> logger)
: base(TimeSpan.FromMinutes(60), DefaultDelay)
: base(logger, TimeSpan.FromMinutes(60), DefaultDelay)
{
_ioHelper = ioHelper;
_mainDom = mainDom;

View File

@@ -247,6 +247,13 @@ namespace Umbraco.Cms.Core.Services.Implement
/// </summary>
private bool TryDeserializeInstructions(CacheInstruction instruction, out JArray jsonInstructions)
{
if (instruction.Instructions is null)
{
_logger.LogError("Failed to deserialize instructions ({DtoId}: 'null').", instruction.Id);
jsonInstructions = null;
return false;
}
try
{
jsonInstructions = JsonConvert.DeserializeObject<JArray>(instruction.Instructions);