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

218 lines
10 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;
using Microsoft.Extensions.Options;
using Umbraco.Core;
using Umbraco.Core.Composing;
2017-09-13 17:35:20 +02:00
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.Models;
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
{
2019-01-03 21:00:28 +01:00
internal 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 _logger;
private readonly IApplicationShutdownRegistry _applicationShutdownRegistry;
2019-01-03 21:00:28 +01:00
private readonly IScopeProvider _scopeProvider;
private readonly HealthCheckCollection _healthChecks;
private readonly HealthCheckNotificationMethodCollection _notifications;
2019-02-14 12:11:06 +01:00
private readonly IUmbracoContextFactory _umbracoContextFactory;
2020-03-16 14:02:08 +01:00
private readonly IHealthChecksSettings _healthChecksSettingsConfig;
private readonly IServerMessenger _serverMessenger;
2020-03-03 07:29:51 +01:00
private readonly IRequestAccessor _requestAccessor;
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,
2017-09-13 17:35:20 +02:00
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger logger,
IApplicationShutdownRegistry applicationShutdownRegistry, IHealthChecksSettings healthChecksSettingsConfig,
IServerMessenger serverMessenger, IRequestAccessor requestAccessor,
IOptions<LoggingSettings> loggingSettings, IOptions<KeepAliveSettings> keepAliveSettings,
IHostingEnvironment hostingEnvironment)
{
_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;
_logger = logger;
_applicationShutdownRegistry = applicationShutdownRegistry;
2019-02-14 12:11:06 +01:00
_umbracoContextFactory = umbracoContextFactory;
2017-09-13 17:35:20 +02:00
_healthChecks = healthChecks;
_notifications = notifications;
2020-03-16 14:02:08 +01:00
_healthChecksSettingsConfig = healthChecksSettingsConfig ?? throw new ArgumentNullException(nameof(healthChecksSettingsConfig));
_serverMessenger = serverMessenger;
2020-03-03 07:29:51 +01:00
_requestAccessor = requestAccessor;
_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
{
// 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);
_healthCheckRunner = new BackgroundTaskRunner<IBackgroundTask>("HealthCheckNotifier", _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, () =>
{
_logger.Debug<SchedulerComponent>("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
2020-03-16 14:02:08 +01:00
var healthCheckConfig = _healthChecksSettingsConfig;
2017-09-13 17:35:20 +02:00
if (healthCheckConfig.NotificationSettings.Enabled)
2019-01-03 21:00:28 +01:00
tasks.Add(RegisterHealthCheckNotifier(healthCheckConfig, _healthChecks, _notifications, _logger));
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
2020-05-07 09:34:16 +02:00
var task = new KeepAlive(_keepAliveRunner, DefaultDelayMilliseconds, FiveMinuteMilliseconds, _requestAccessor, _mainDom, keepAliveSettings, _logger, _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, _logger, _serverMessenger);
2017-09-13 17:35:20 +02:00
_publishingRunner.TryAdd(task);
return task;
}
2019-02-14 12:11:06 +01:00
2020-03-16 14:02:08 +01:00
private IBackgroundTask RegisterHealthCheckNotifier(IHealthChecksSettings healthCheckSettingsConfig,
2017-09-13 17:35:20 +02:00
HealthCheckCollection healthChecks, HealthCheckNotificationMethodCollection notifications,
2019-01-03 21:00:28 +01:00
IProfilingLogger logger)
2017-09-13 17:35:20 +02:00
{
// If first run time not set, start with just small delay after application start
int delayInMilliseconds;
2020-03-16 14:02:08 +01:00
if (string.IsNullOrEmpty(healthCheckSettingsConfig.NotificationSettings.FirstRunTime))
2017-09-13 17:35:20 +02:00
{
delayInMilliseconds = DefaultDelayMilliseconds;
2017-09-13 17:35:20 +02:00
}
else
{
// Otherwise start at scheduled time
2020-03-16 14:02:08 +01:00
delayInMilliseconds = DateTime.Now.PeriodicMinutesFrom(healthCheckSettingsConfig.NotificationSettings.FirstRunTime) * 60 * 1000;
if (delayInMilliseconds < DefaultDelayMilliseconds)
2017-09-13 17:35:20 +02:00
{
delayInMilliseconds = DefaultDelayMilliseconds;
2017-09-13 17:35:20 +02:00
}
}
2020-03-16 14:02:08 +01:00
var periodInMilliseconds = healthCheckSettingsConfig.NotificationSettings.PeriodInHours * 60 * 60 * 1000;
2020-08-06 12:59:21 +02:00
var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _mainDom, logger, _healthChecksSettingsConfig, _serverRegistrar, _runtime, _scopeProvider);
2019-01-15 17:27:18 +01:00
_healthCheckRunner.TryAdd(task);
2017-09-13 17:35:20 +02:00
return task;
}
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, settings, _scopeProvider, _logger);
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, _logger);
_scrubberRunner.TryAdd(task);
return task;
}
2014-06-25 11:00:11 +10:00
}
}