Files
Umbraco-CMS/src/Umbraco.Infrastructure/Scheduling/SchedulerComponent.cs

188 lines
8.6 KiB
C#
Raw Normal View History

2017-09-13 17:35:20 +02:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
2020-09-15 15:14:44 +02:00
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.Models;
Netcore/feature/healthcheck replaceconfiglogic (#8934) * Started moving to JSON instead of config. Mild refactoring but overall keeping it the same, except for injecting IConfiguration and JSON parsing instead of XML Tests currently unaffected, need to increase coverage * Moved to constants for appsettings keys Moved from IConfiguration to global settings - later to be replaced with IOptions Updated translation messages Installed IOptions ready for new PR Updated to new interface, IConfigurationService * Post-merge fix * Namespace move from Umbraco.Web to Umbraco.Core where appropriate * Renamed abstractsettings (from abstractconfig) Moving out of configservice into the POCO config check * Made the IIsCustomErrors healthcheck as obsolete, as no web.config setting). Investigate reintroducing this check in the .NET Core way (UseDevelopment). Reducing use of abstractsettings as not needed - we don't need a config service to read the config settings anymore as they're all explicit POCOs. Consolidated health-checks in project. * Removed test views that weren't meant to be added * Returned to use of abstractsettings with different use * Moved more health checks into correct folder/namespace, and enum into their own file * Correct namespace * Git history/compare lost due to file move, temporarily moving back to original folder. Will do another PR to move after this * Use existing GetStatus in abstract check for Debug mode * Updating to return to previous logic and putting files back into line * Macro errors returned to previous logic * Reuse abstractsettings class * Swapped order to assist with reviewing PR * Updated to include itempath * Not implemented comment to avoid confusion Implemented NotificationEmailCheck * Changed to IOptionsMonitor as per PR comments. Removed configurationservice as we need to rethink the fixing strategy. Updated logger. Needs to show fix message instead of fixing. Temporary fix for IIS version * Switched to IOptionsMonitor for all * No longer attempts to actually fix header in config. Still need to show suggestions. Co-authored-by: Elitsa Marinovska <elm@umbraco.dk>
2020-10-21 10:29:25 +01:00
using Umbraco.Core.HealthCheck;
using Umbraco.Core.Hosting;
2014-06-25 11:00:11 +10:00
using Umbraco.Core.Logging;
2017-05-12 14:49:44 +02:00
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
2017-09-13 17:35:20 +02:00
using Umbraco.Web.HealthCheck;
using Umbraco.Web.Routing;
namespace Umbraco.Web.Scheduling
{
public sealed class SchedulerComponent : IComponent
2014-06-25 11:00:11 +10:00
{
private const int DefaultDelayMilliseconds = 180000; // 3 mins
private const int OneMinuteMilliseconds = 60000;
private const int FiveMinuteMilliseconds = 300000;
private const int OneHourMilliseconds = 3600000;
2019-01-03 21:00:28 +01:00
private readonly IRuntimeState _runtime;
private readonly IMainDom _mainDom;
private readonly IServerRegistrar _serverRegistrar;
2019-01-03 21:00:28 +01:00
private readonly IContentService _contentService;
private readonly IAuditService _auditService;
private readonly IProfilingLogger _profilingLogger;
private readonly ILogger<SchedulerComponent> _logger;
2020-09-15 15:14:44 +02:00
private readonly ILoggerFactory _loggerFactory;
private readonly IApplicationShutdownRegistry _applicationShutdownRegistry;
2019-01-03 21:00:28 +01:00
private readonly IScopeProvider _scopeProvider;
2019-02-14 12:11:06 +01:00
private readonly IUmbracoContextFactory _umbracoContextFactory;
private readonly IServerMessenger _serverMessenger;
2020-03-03 07:29:51 +01:00
private readonly IRequestAccessor _requestAccessor;
private readonly IBackofficeSecurityFactory _backofficeSecurityFactory;
private readonly LoggingSettings _loggingSettings;
private readonly KeepAliveSettings _keepAliveSettings;
private readonly IHostingEnvironment _hostingEnvironment;
2019-01-03 21:00:28 +01:00
2019-01-07 09:30:47 +01:00
private BackgroundTaskRunner<IBackgroundTask> _keepAliveRunner;
private BackgroundTaskRunner<IBackgroundTask> _publishingRunner;
private BackgroundTaskRunner<IBackgroundTask> _scrubberRunner;
private BackgroundTaskRunner<IBackgroundTask> _fileCleanupRunner;
2019-01-07 09:30:47 +01:00
private BackgroundTaskRunner<IBackgroundTask> _healthCheckRunner;
private bool _started;
private object _locker = new object();
private IBackgroundTask[] _tasks;
public SchedulerComponent(IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar,
2018-11-08 16:33:19 +01:00
IContentService contentService, IAuditService auditService,
IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger profilingLogger, ILoggerFactory loggerFactory,
IApplicationShutdownRegistry applicationShutdownRegistry,
IServerMessenger serverMessenger, IRequestAccessor requestAccessor,
IOptions<LoggingSettings> loggingSettings, IOptions<KeepAliveSettings> keepAliveSettings,
IHostingEnvironment hostingEnvironment,
IBackofficeSecurityFactory backofficeSecurityFactory)
{
_runtime = runtime;
_mainDom = mainDom;
_serverRegistrar = serverRegistrar;
2017-09-13 17:35:20 +02:00
_contentService = contentService;
_auditService = auditService;
2017-05-12 14:49:44 +02:00
_scopeProvider = scopeProvider;
_profilingLogger = profilingLogger;
2020-09-15 15:14:44 +02:00
_loggerFactory = loggerFactory;
_logger = loggerFactory.CreateLogger<SchedulerComponent>();
_applicationShutdownRegistry = applicationShutdownRegistry;
2019-02-14 12:11:06 +01:00
_umbracoContextFactory = umbracoContextFactory;
_serverMessenger = serverMessenger;
2020-03-03 07:29:51 +01:00
_requestAccessor = requestAccessor;
_backofficeSecurityFactory = backofficeSecurityFactory;
_loggingSettings = loggingSettings.Value;
_keepAliveSettings = keepAliveSettings.Value;
_hostingEnvironment = hostingEnvironment;
2019-01-07 09:30:47 +01:00
}
2017-09-13 17:35:20 +02:00
2019-01-07 09:30:47 +01:00
public void Initialize()
2019-01-07 10:43:28 +01:00
{
var logger = _loggerFactory.CreateLogger<BackgroundTaskRunner<IBackgroundTask>>();
// backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly
_keepAliveRunner = new BackgroundTaskRunner<IBackgroundTask>("KeepAlive", logger, _applicationShutdownRegistry);
_publishingRunner = new BackgroundTaskRunner<IBackgroundTask>("ScheduledPublishing", logger, _applicationShutdownRegistry);
_scrubberRunner = new BackgroundTaskRunner<IBackgroundTask>("LogScrubber", logger, _applicationShutdownRegistry);
_fileCleanupRunner = new BackgroundTaskRunner<IBackgroundTask>("TempFileCleanup", logger, _applicationShutdownRegistry);
// we will start the whole process when a successful request is made
2020-03-03 07:29:51 +01:00
_requestAccessor.RouteAttempt += RegisterBackgroundTasksOnce;
}
2019-01-07 09:30:47 +01:00
public void Terminate()
{
// the AppDomain / maindom / whatever takes care of stopping background task runners
2019-01-07 09:30:47 +01:00
}
2018-03-27 10:04:07 +02:00
private void RegisterBackgroundTasksOnce(object sender, RoutableAttemptEventArgs e)
{
switch (e.Outcome)
{
case EnsureRoutableOutcome.IsRoutable:
case EnsureRoutableOutcome.NotDocumentRequest:
2020-03-04 07:50:37 +01:00
_requestAccessor.RouteAttempt -= RegisterBackgroundTasksOnce;
2017-09-13 17:35:20 +02:00
RegisterBackgroundTasks();
break;
}
}
2017-09-13 17:35:20 +02:00
private void RegisterBackgroundTasks()
{
LazyInitializer.EnsureInitialized(ref _tasks, ref _started, ref _locker, () =>
{
2020-09-15 15:14:44 +02:00
_logger.LogDebug("Initializing the scheduler");
2017-09-13 17:35:20 +02:00
var tasks = new List<IBackgroundTask>();
if (_keepAliveSettings.DisableKeepAliveTask == false)
{
tasks.Add(RegisterKeepAlive(_keepAliveSettings));
}
2017-09-13 17:35:20 +02:00
tasks.Add(RegisterScheduledPublishing());
tasks.Add(RegisterLogScrubber(_loggingSettings));
tasks.Add(RegisterTempFileCleanup());
2014-06-25 11:00:11 +10:00
return tasks.ToArray();
});
}
2017-09-13 17:35:20 +02:00
private IBackgroundTask RegisterKeepAlive(KeepAliveSettings keepAliveSettings)
2017-09-13 17:35:20 +02:00
{
// ping/keepalive
// on all servers
var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _requestAccessor, _mainDom, Options.Create(keepAliveSettings), _loggerFactory.CreateLogger<KeepAlive>(), _profilingLogger, _serverRegistrar);
2017-09-13 17:35:20 +02:00
_keepAliveRunner.TryAdd(task);
return task;
}
private IBackgroundTask RegisterScheduledPublishing()
{
// scheduled publishing/unpublishing
2018-10-02 11:14:04 +02:00
// install on all, will only run on non-replica servers
var task = new ScheduledPublishing(_publishingRunner, DefaultDelayMilliseconds, OneMinuteMilliseconds, _runtime, _mainDom, _serverRegistrar, _contentService, _umbracoContextFactory, _loggerFactory.CreateLogger<ScheduledPublishing>(), _serverMessenger, _backofficeSecurityFactory);
2017-09-13 17:35:20 +02:00
_publishingRunner.TryAdd(task);
return task;
}
2019-02-14 12:11:06 +01:00
private IBackgroundTask RegisterLogScrubber(LoggingSettings settings)
2017-09-13 17:35:20 +02:00
{
// log scrubbing
2018-10-02 11:14:04 +02:00
// install on all, will only run on non-replica servers
var task = new LogScrubber(_scrubberRunner, DefaultDelayMilliseconds, LogScrubber.GetLogScrubbingInterval(), _mainDom, _serverRegistrar, _auditService, Options.Create(settings), _scopeProvider, _profilingLogger, _loggerFactory.CreateLogger<LogScrubber>());
2017-09-13 17:35:20 +02:00
_scrubberRunner.TryAdd(task);
return task;
}
private IBackgroundTask RegisterTempFileCleanup()
{
var tempFolderPaths = new[]
{
_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempFileUploads)
};
foreach (var tempFolderPath in tempFolderPaths)
{
//ensure it exists
Directory.CreateDirectory(tempFolderPath);
}
// temp file cleanup, will run on all servers - even though file upload should only be handled on the master, this will
// ensure that in the case it happes on replicas that they are cleaned up.
var task = new TempFileCleanup(_fileCleanupRunner, DefaultDelayMilliseconds, OneHourMilliseconds,
tempFolderPaths.Select(x=>new DirectoryInfo(x)),
TimeSpan.FromDays(1), //files that are over a day old
_mainDom, _profilingLogger, _loggerFactory.CreateLogger<TempFileCleanup>());
_scrubberRunner.TryAdd(task);
return task;
}
2014-06-25 11:00:11 +10:00
}
}