2017-09-13 17:35:20 +02:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2019-09-18 22:03:31 +10:00
|
|
|
|
using System.IO;
|
2020-06-30 08:14:26 +02:00
|
|
|
|
using System.Linq;
|
2016-03-10 15:17:46 +01:00
|
|
|
|
using System.Threading;
|
2020-09-15 15:14:44 +02:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2020-08-20 22:18:50 +01:00
|
|
|
|
using Microsoft.Extensions.Options;
|
2014-06-20 14:34:21 +10:00
|
|
|
|
using Umbraco.Core;
|
2018-12-12 17:49:24 +01:00
|
|
|
|
using Umbraco.Core.Composing;
|
2017-09-13 17:35:20 +02:00
|
|
|
|
using Umbraco.Core.Configuration.HealthChecks;
|
2020-08-20 22:18:50 +01:00
|
|
|
|
using Umbraco.Core.Configuration.Models;
|
2020-01-08 09:01:58 +01:00
|
|
|
|
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;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
using Umbraco.Core.Services;
|
2020-02-18 13:34:31 +01:00
|
|
|
|
using Umbraco.Core.Sync;
|
2017-09-13 17:35:20 +02:00
|
|
|
|
using Umbraco.Web.HealthCheck;
|
2016-03-10 15:17:46 +01:00
|
|
|
|
using Umbraco.Web.Routing;
|
2014-06-20 14:34:21 +10:00
|
|
|
|
|
|
|
|
|
|
namespace Umbraco.Web.Scheduling
|
|
|
|
|
|
{
|
2020-09-02 18:10:29 +10:00
|
|
|
|
public sealed class SchedulerComponent : IComponent
|
2014-06-25 11:00:11 +10:00
|
|
|
|
{
|
2019-10-31 15:44:50 +11: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;
|
2020-03-25 15:06:22 +11:00
|
|
|
|
private readonly IMainDom _mainDom;
|
|
|
|
|
|
private readonly IServerRegistrar _serverRegistrar;
|
2019-01-03 21:00:28 +01:00
|
|
|
|
private readonly IContentService _contentService;
|
|
|
|
|
|
private readonly IAuditService _auditService;
|
2020-09-29 10:42:06 +02:00
|
|
|
|
private readonly IProfilingLogger _profilingLogger;
|
2020-09-22 13:44:22 +02:00
|
|
|
|
private readonly ILogger<SchedulerComponent> _logger;
|
2020-09-15 15:14:44 +02:00
|
|
|
|
private readonly ILoggerFactory _loggerFactory;
|
2020-06-30 08:14:26 +02:00
|
|
|
|
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-08-24 09:29:40 +02:00
|
|
|
|
private readonly HealthChecksSettings _healthChecksSettings;
|
2020-02-18 13:34:31 +01:00
|
|
|
|
private readonly IServerMessenger _serverMessenger;
|
2020-03-03 07:29:51 +01:00
|
|
|
|
private readonly IRequestAccessor _requestAccessor;
|
2020-09-22 13:19:54 +02:00
|
|
|
|
private readonly IBackofficeSecurityFactory _backofficeSecurityFactory;
|
2020-08-20 22:18:50 +01:00
|
|
|
|
private readonly LoggingSettings _loggingSettings;
|
|
|
|
|
|
private readonly KeepAliveSettings _keepAliveSettings;
|
2020-06-30 08:14:26 +02:00
|
|
|
|
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;
|
2019-09-18 22:03:31 +10:00
|
|
|
|
private BackgroundTaskRunner<IBackgroundTask> _fileCleanupRunner;
|
2019-01-07 09:30:47 +01:00
|
|
|
|
private BackgroundTaskRunner<IBackgroundTask> _healthCheckRunner;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
|
|
|
|
|
|
private bool _started;
|
2016-03-10 15:17:46 +01:00
|
|
|
|
private object _locker = new object();
|
|
|
|
|
|
private IBackgroundTask[] _tasks;
|
2014-06-20 14:34:21 +10:00
|
|
|
|
|
2020-03-25 15:06:22 +11:00
|
|
|
|
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,
|
2020-09-29 10:42:06 +02:00
|
|
|
|
IScopeProvider scopeProvider, IUmbracoContextFactory umbracoContextFactory, IProfilingLogger profilingLogger , ILoggerFactory loggerFactory,
|
2020-08-24 09:29:40 +02:00
|
|
|
|
IApplicationShutdownRegistry applicationShutdownRegistry, IOptions<HealthChecksSettings> healthChecksSettings,
|
2020-06-30 08:14:26 +02:00
|
|
|
|
IServerMessenger serverMessenger, IRequestAccessor requestAccessor,
|
2020-08-23 23:36:48 +02:00
|
|
|
|
IOptions<LoggingSettings> loggingSettings, IOptions<KeepAliveSettings> keepAliveSettings,
|
2020-09-22 13:19:54 +02:00
|
|
|
|
IHostingEnvironment hostingEnvironment,
|
|
|
|
|
|
IBackofficeSecurityFactory backofficeSecurityFactory)
|
2014-06-20 14:34:21 +10:00
|
|
|
|
{
|
2016-09-01 19:06:08 +02:00
|
|
|
|
_runtime = runtime;
|
2020-03-25 15:06:22 +11:00
|
|
|
|
_mainDom = mainDom;
|
|
|
|
|
|
_serverRegistrar = serverRegistrar;
|
2017-09-13 17:35:20 +02:00
|
|
|
|
_contentService = contentService;
|
2016-09-01 19:06:08 +02:00
|
|
|
|
_auditService = auditService;
|
2017-05-12 14:49:44 +02:00
|
|
|
|
_scopeProvider = scopeProvider;
|
2020-09-29 10:42:06 +02:00
|
|
|
|
_profilingLogger = profilingLogger ;
|
2020-09-15 15:14:44 +02:00
|
|
|
|
_loggerFactory = loggerFactory;
|
2020-09-21 09:52:58 +02:00
|
|
|
|
_logger = loggerFactory.CreateLogger<SchedulerComponent>();
|
2020-06-30 08:14:26 +02:00
|
|
|
|
_applicationShutdownRegistry = applicationShutdownRegistry;
|
2019-02-14 12:11:06 +01:00
|
|
|
|
_umbracoContextFactory = umbracoContextFactory;
|
2014-06-20 14:34:21 +10:00
|
|
|
|
|
2017-09-13 17:35:20 +02:00
|
|
|
|
_healthChecks = healthChecks;
|
|
|
|
|
|
_notifications = notifications;
|
2020-08-24 09:29:40 +02:00
|
|
|
|
_healthChecksSettings = healthChecksSettings.Value ?? throw new ArgumentNullException(nameof(healthChecksSettings));
|
2020-02-18 13:34:31 +01:00
|
|
|
|
_serverMessenger = serverMessenger;
|
2020-03-03 07:29:51 +01:00
|
|
|
|
_requestAccessor = requestAccessor;
|
2020-09-22 13:19:54 +02:00
|
|
|
|
_backofficeSecurityFactory = backofficeSecurityFactory;
|
2020-08-20 22:18:50 +01:00
|
|
|
|
_loggingSettings = loggingSettings.Value;
|
|
|
|
|
|
_keepAliveSettings = keepAliveSettings.Value;
|
2020-06-30 08:14:26 +02:00
|
|
|
|
_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
|
|
|
|
{
|
2020-09-17 13:14:02 +02:00
|
|
|
|
var logger = _loggerFactory.CreateLogger<BackgroundTaskRunner<IBackgroundTask>>();
|
2016-03-10 15:17:46 +01:00
|
|
|
|
// backgrounds runners are web aware, if the app domain dies, these tasks will wind down correctly
|
2020-09-17 13:14:02 +02:00
|
|
|
|
_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);
|
2016-03-10 15:17:46 +01:00
|
|
|
|
|
2016-09-01 19:06:08 +02:00
|
|
|
|
// we will start the whole process when a successful request is made
|
2020-03-03 07:29:51 +01:00
|
|
|
|
_requestAccessor.RouteAttempt += RegisterBackgroundTasksOnce;
|
2016-03-10 15:17:46 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-01-07 09:30:47 +01:00
|
|
|
|
public void Terminate()
|
|
|
|
|
|
{
|
2019-01-26 10:52:19 -05:00
|
|
|
|
// 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)
|
2016-03-10 15:17:46 +01:00
|
|
|
|
{
|
|
|
|
|
|
switch (e.Outcome)
|
2014-11-12 16:00:17 +11:00
|
|
|
|
{
|
2016-03-10 15:17:46 +01:00
|
|
|
|
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();
|
2016-03-10 15:17:46 +01:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2014-11-12 16:00:17 +11:00
|
|
|
|
|
2017-09-13 17:35:20 +02:00
|
|
|
|
private void RegisterBackgroundTasks()
|
2016-03-10 15:17:46 +01:00
|
|
|
|
{
|
|
|
|
|
|
LazyInitializer.EnsureInitialized(ref _tasks, ref _started, ref _locker, () =>
|
|
|
|
|
|
{
|
2020-09-15 15:14:44 +02:00
|
|
|
|
_logger.LogDebug("Initializing the scheduler");
|
2016-03-10 15:17:46 +01:00
|
|
|
|
|
2017-09-13 17:35:20 +02:00
|
|
|
|
var tasks = new List<IBackgroundTask>();
|
2014-06-20 14:34:21 +10:00
|
|
|
|
|
2020-03-12 08:28:31 +01:00
|
|
|
|
if (_keepAliveSettings.DisableKeepAliveTask == false)
|
2019-12-20 02:14:42 -05:00
|
|
|
|
{
|
2020-03-12 08:28:31 +01:00
|
|
|
|
tasks.Add(RegisterKeepAlive(_keepAliveSettings));
|
2019-12-20 02:14:42 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-13 17:35:20 +02:00
|
|
|
|
tasks.Add(RegisterScheduledPublishing());
|
2020-03-12 08:24:02 +01:00
|
|
|
|
tasks.Add(RegisterLogScrubber(_loggingSettings));
|
2019-09-18 22:03:31 +10:00
|
|
|
|
tasks.Add(RegisterTempFileCleanup());
|
2014-06-25 11:00:11 +10:00
|
|
|
|
|
2020-08-24 09:29:40 +02:00
|
|
|
|
var healthCheckConfig = _healthChecksSettings;
|
2017-09-13 17:35:20 +02:00
|
|
|
|
if (healthCheckConfig.NotificationSettings.Enabled)
|
2020-09-29 10:42:06 +02:00
|
|
|
|
tasks.Add(RegisterHealthCheckNotifier(healthCheckConfig, _healthChecks, _notifications, _profilingLogger));
|
2015-02-06 18:10:19 +01:00
|
|
|
|
|
2016-03-10 15:17:46 +01:00
|
|
|
|
return tasks.ToArray();
|
|
|
|
|
|
});
|
2014-11-12 16:00:17 +11:00
|
|
|
|
}
|
2017-09-13 17:35:20 +02:00
|
|
|
|
|
2020-08-20 22:18:50 +01:00
|
|
|
|
private IBackgroundTask RegisterKeepAlive(KeepAliveSettings keepAliveSettings)
|
2017-09-13 17:35:20 +02:00
|
|
|
|
{
|
|
|
|
|
|
// ping/keepalive
|
|
|
|
|
|
// on all servers
|
2020-09-29 10:42:06 +02:00
|
|
|
|
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
|
2020-09-22 13:44:22 +02:00
|
|
|
|
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
|
|
|
|
|
2020-08-24 09:29:40 +02:00
|
|
|
|
private IBackgroundTask RegisterHealthCheckNotifier(HealthChecksSettings 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
|
|
|
|
{
|
2019-10-31 15:44:50 +11: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;
|
2019-10-31 15:44:50 +11:00
|
|
|
|
if (delayInMilliseconds < DefaultDelayMilliseconds)
|
2017-09-13 17:35:20 +02:00
|
|
|
|
{
|
2019-10-31 15:44:50 +11: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-09-18 12:53:06 +02:00
|
|
|
|
var task = new HealthCheckNotifier(_healthCheckRunner, delayInMilliseconds, periodInMilliseconds, healthChecks, notifications, _mainDom, logger, _loggerFactory.CreateLogger<HealthCheckNotifier>(), _healthChecksSettings, _serverRegistrar, _runtime, _scopeProvider);
|
2019-01-15 17:27:18 +01:00
|
|
|
|
_healthCheckRunner.TryAdd(task);
|
2017-09-13 17:35:20 +02:00
|
|
|
|
return task;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-08-20 22:18:50 +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
|
2020-09-29 10:42:06 +02:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
2019-09-18 22:03:31 +10:00
|
|
|
|
|
|
|
|
|
|
private IBackgroundTask RegisterTempFileCleanup()
|
|
|
|
|
|
{
|
2020-06-30 08:14:26 +02:00
|
|
|
|
|
|
|
|
|
|
var tempFolderPaths = new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempFileUploads)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var tempFolderPath in tempFolderPaths)
|
|
|
|
|
|
{
|
|
|
|
|
|
//ensure it exists
|
|
|
|
|
|
Directory.CreateDirectory(tempFolderPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2019-09-18 22:03:31 +10:00
|
|
|
|
// 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.
|
2019-10-31 15:44:50 +11:00
|
|
|
|
var task = new TempFileCleanup(_fileCleanupRunner, DefaultDelayMilliseconds, OneHourMilliseconds,
|
2020-06-30 08:14:26 +02:00
|
|
|
|
tempFolderPaths.Select(x=>new DirectoryInfo(x)),
|
2019-09-18 22:03:31 +10:00
|
|
|
|
TimeSpan.FromDays(1), //files that are over a day old
|
2020-09-29 10:42:06 +02:00
|
|
|
|
_mainDom, _profilingLogger, _loggerFactory.CreateLogger<TempFileCleanup>());
|
2019-09-18 22:03:31 +10:00
|
|
|
|
_scrubberRunner.TryAdd(task);
|
|
|
|
|
|
return task;
|
|
|
|
|
|
}
|
2014-06-25 11:00:11 +10:00
|
|
|
|
}
|
2014-06-20 14:34:21 +10:00
|
|
|
|
}
|