diff --git a/src/Umbraco.Cms.Api.Common/DependencyInjection/UmbracoBuilderAuthExtensions.cs b/src/Umbraco.Cms.Api.Common/DependencyInjection/UmbracoBuilderAuthExtensions.cs index dac3717569..f3e855c6a0 100644 --- a/src/Umbraco.Cms.Api.Common/DependencyInjection/UmbracoBuilderAuthExtensions.cs +++ b/src/Umbraco.Cms.Api.Common/DependencyInjection/UmbracoBuilderAuthExtensions.cs @@ -4,7 +4,9 @@ using Microsoft.IdentityModel.Tokens; using Umbraco.Cms.Api.Common.Security; using Umbraco.Cms.Core; using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs; using Umbraco.Cms.Infrastructure.HostedServices; +using Umbraco.Extensions; namespace Umbraco.Cms.Api.Common.DependencyInjection; @@ -12,7 +14,7 @@ public static class UmbracoBuilderAuthExtensions { public static IUmbracoBuilder AddUmbracoOpenIddict(this IUmbracoBuilder builder) { - if (builder.Services.Any(x=>x.ImplementationType == typeof(OpenIddictCleanup)) is false) + if (builder.Services.Any(x=>x.ImplementationType == typeof(OpenIddictCleanupJob)) is false) { ConfigureOpenIddict(builder); } @@ -102,6 +104,6 @@ public static class UmbracoBuilderAuthExtensions options.UseDataProtection(); }); - builder.Services.AddHostedService(); + builder.Services.AddRecurringBackgroundJob(); } } diff --git a/src/Umbraco.Infrastructure/HostedServices/OpenIddictCleanup.cs b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/OpenIddictCleanupJob.cs similarity index 63% rename from src/Umbraco.Infrastructure/HostedServices/OpenIddictCleanup.cs rename to src/Umbraco.Infrastructure/BackgroundJobs/Jobs/OpenIddictCleanupJob.cs index c65f687e16..7cb0575177 100644 --- a/src/Umbraco.Infrastructure/HostedServices/OpenIddictCleanup.cs +++ b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/OpenIddictCleanupJob.cs @@ -2,38 +2,34 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using OpenIddict.Abstractions; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Services; -namespace Umbraco.Cms.Infrastructure.HostedServices; +namespace Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs; // port of the OpenIddict Quartz job for cleaning up - see https://github.com/openiddict/openiddict-core/tree/dev/src/OpenIddict.Quartz -public class OpenIddictCleanup : RecurringHostedServiceBase +public class OpenIddictCleanupJob : IRecurringBackgroundJob { + public TimeSpan Period { get => TimeSpan.FromHours(1); } + public TimeSpan Delay { get => TimeSpan.FromMinutes(5); } + + // No-op event as the period never changes on this job + public event EventHandler PeriodChanged { add { } remove { } } + + // keep tokens and authorizations in the database for 7 days // - NOTE: this is NOT the same as access token lifetime, which is likely very short private const int LifespanInSeconds = 7 * 24 * 60 * 60; - private readonly ILogger _logger; + private readonly ILogger _logger; private readonly IServiceProvider _provider; - private readonly IRuntimeState _runtimeState; - public OpenIddictCleanup( - ILogger logger, IServiceProvider provider, IRuntimeState runtimeState) - : base(logger, TimeSpan.FromHours(1), TimeSpan.FromMinutes(5)) + public OpenIddictCleanupJob(ILogger logger, IServiceProvider provider) { _logger = logger; _provider = provider; - _runtimeState = runtimeState; } - public override async Task PerformExecuteAsync(object? state) + public async Task RunJobAsync() { - if (_runtimeState.Level < RuntimeLevel.Run) - { - return; - } - // hosted services are registered as singletons, but this particular one consumes scoped services... so // we have to fetch the service dependencies manually using a new scope per invocation. IServiceScope scope = _provider.CreateScope(); @@ -42,7 +38,7 @@ public class OpenIddictCleanup : RecurringHostedServiceBase try { IOpenIddictTokenManager tokenManager = scope.ServiceProvider.GetService() - ?? throw new ConfigurationErrorsException($"Could not retrieve an {nameof(IOpenIddictTokenManager)} service from the current scope"); + ?? throw new ConfigurationErrorsException($"Could not retrieve an {nameof(IOpenIddictTokenManager)} service from the current scope"); await tokenManager.PruneAsync(threshold); } catch (Exception exception) @@ -53,7 +49,7 @@ public class OpenIddictCleanup : RecurringHostedServiceBase try { IOpenIddictAuthorizationManager authorizationManager = scope.ServiceProvider.GetService() - ?? throw new ConfigurationErrorsException($"Could not retrieve an {nameof(IOpenIddictAuthorizationManager)} service from the current scope"); + ?? throw new ConfigurationErrorsException($"Could not retrieve an {nameof(IOpenIddictAuthorizationManager)} service from the current scope"); await authorizationManager.PruneAsync(threshold); } catch (Exception exception) diff --git a/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/ReportSiteJob.cs b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/ReportSiteJob.cs index 5d39b57add..1a35c4199c 100644 --- a/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/ReportSiteJob.cs +++ b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/ReportSiteJob.cs @@ -1,13 +1,6 @@ using System.Text; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Sync; using Umbraco.Cms.Core.Telemetry; using Umbraco.Cms.Core.Telemetry.Models; @@ -28,14 +21,17 @@ public class ReportSiteJob : IRecurringBackgroundJob private static HttpClient _httpClient = new(); private readonly ILogger _logger; private readonly ITelemetryService _telemetryService; - + private readonly IJsonSerializer _jsonSerializer; + public ReportSiteJob( ILogger logger, - ITelemetryService telemetryService) + ITelemetryService telemetryService, + IJsonSerializer jsonSerializer) { _logger = logger; _telemetryService = telemetryService; + _jsonSerializer = jsonSerializer; _httpClient = new HttpClient(); } @@ -70,7 +66,7 @@ public class ReportSiteJob : IRecurringBackgroundJob using (var request = new HttpRequestMessage(HttpMethod.Post, "installs/")) { - request.Content = new StringContent(JsonConvert.SerializeObject(telemetryReportData), Encoding.UTF8, + request.Content = new StringContent(_jsonSerializer.Serialize(telemetryReportData), Encoding.UTF8, "application/json"); // Make a HTTP Post to telemetry service diff --git a/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/TemporaryFileCleanupJob.cs b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/TemporaryFileCleanupJob.cs new file mode 100644 index 0000000000..0c4e331484 --- /dev/null +++ b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/TemporaryFileCleanupJob.cs @@ -0,0 +1,46 @@ +using Microsoft.Extensions.Logging; +using Umbraco.Cms.Core.Services; + +namespace Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs; + +public class TemporaryFileCleanupJob : IRecurringBackgroundJob +{ + public TimeSpan Period { get => TimeSpan.FromMinutes(5); } + public TimeSpan Delay { get => TimeSpan.FromMinutes(5); } + + // No-op event as the period never changes on this job + public event EventHandler PeriodChanged { add { } remove { } } + + private readonly ILogger _logger; + private readonly ITemporaryFileService _service; + + + /// + /// Initializes a new instance of the class. + /// + public TemporaryFileCleanupJob( + ILogger logger, + ITemporaryFileService temporaryFileService) + { + _logger = logger; + _service = temporaryFileService; + } + + /// + /// Runs the background task to send the anonymous ID + /// to telemetry service + /// + public async Task RunJobAsync() + { + var count = (await _service.CleanUpOldTempFiles()).Count(); + + if (count > 0) + { + _logger.LogDebug("Deleted {Count} temporary file(s)", count); + } + else + { + _logger.LogDebug("Task complete, no items were deleted"); + } + } +} diff --git a/src/Umbraco.Infrastructure/HostedServices/ContentVersionCleanup.cs b/src/Umbraco.Infrastructure/HostedServices/ContentVersionCleanup.cs deleted file mode 100644 index 1ecfcbf926..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/ContentVersionCleanup.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; - -namespace Umbraco.Cms.Infrastructure.HostedServices; - -/// -/// Recurring hosted service that executes the content history cleanup. -/// -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.ContentVersionCleanupJob instead. This class will be removed in Umbraco 14.")] -public class ContentVersionCleanup : RecurringHostedServiceBase -{ - private readonly ILogger _logger; - private readonly IMainDom _mainDom; - private readonly IRuntimeState _runtimeState; - private readonly IServerRoleAccessor _serverRoleAccessor; - private readonly IContentVersionService _service; - private readonly IOptionsMonitor _settingsMonitor; - - /// - /// Initializes a new instance of the class. - /// - public ContentVersionCleanup( - IRuntimeState runtimeState, - ILogger logger, - IOptionsMonitor settingsMonitor, - IContentVersionService service, - IMainDom mainDom, - IServerRoleAccessor serverRoleAccessor) - : base(logger, TimeSpan.FromHours(1), TimeSpan.FromMinutes(3)) - { - _runtimeState = runtimeState; - _logger = logger; - _settingsMonitor = settingsMonitor; - _service = service; - _mainDom = mainDom; - _serverRoleAccessor = serverRoleAccessor; - } - - /// - public override Task PerformExecuteAsync(object? state) - { - // Globally disabled by feature flag - if (!_settingsMonitor.CurrentValue.ContentVersionCleanupPolicy.EnableCleanup) - { - _logger.LogInformation( - "ContentVersionCleanup task will not run as it has been globally disabled via configuration"); - return Task.CompletedTask; - } - - if (_runtimeState.Level != RuntimeLevel.Run) - { - return Task.FromResult(true); // repeat... - } - - // Don't run on replicas nor unknown role servers - switch (_serverRoleAccessor.CurrentServerRole) - { - case ServerRole.Subscriber: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on subscriber servers"); - } - return Task.CompletedTask; - case ServerRole.Unknown: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on servers with unknown role"); - } - return Task.CompletedTask; - case ServerRole.Single: - case ServerRole.SchedulingPublisher: - default: - break; - } - - // Ensure we do not run if not main domain, but do NOT lock it - if (!_mainDom.IsMainDom) - { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run if not MainDom"); - } - return Task.FromResult(false); // do NOT repeat, going down - } - - var count = _service.PerformContentVersionCleanup(DateTime.Now).Count; - - if (count > 0) - { - _logger.LogInformation("Deleted {count} ContentVersion(s)", count); - } - else - { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Task complete, no items were Deleted"); - } - } - - return Task.FromResult(true); - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs b/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs deleted file mode 100644 index 5ee76d1a18..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/HealthCheckNotifier.cs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.HealthChecks; -using Umbraco.Cms.Core.HealthChecks.NotificationMethods; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Infrastructure.HostedServices; - -/// -/// Hosted service implementation for recurring health check notifications. -/// -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.HealthCheckNotifierJob instead. This class will be removed in Umbraco 14.")] -public class HealthCheckNotifier : RecurringHostedServiceBase -{ - private readonly HealthCheckCollection _healthChecks; - private readonly ILogger _logger; - private readonly IMainDom _mainDom; - private readonly HealthCheckNotificationMethodCollection _notifications; - private readonly IProfilingLogger _profilingLogger; - private readonly IRuntimeState _runtimeState; - private readonly ICoreScopeProvider _scopeProvider; - private readonly IServerRoleAccessor _serverRegistrar; - private HealthChecksSettings _healthChecksSettings; - - /// - /// Initializes a new instance of the class. - /// - /// The configuration for health check settings. - /// The collection of healthchecks. - /// The collection of healthcheck notification methods. - /// Representation of the state of the Umbraco runtime. - /// Provider of server registrations to the distributed cache. - /// Representation of the main application domain. - /// Provides scopes for database operations. - /// The typed logger. - /// The profiling logger. - /// Parser of crontab expressions. - public HealthCheckNotifier( - IOptionsMonitor healthChecksSettings, - HealthCheckCollection healthChecks, - HealthCheckNotificationMethodCollection notifications, - IRuntimeState runtimeState, - IServerRoleAccessor serverRegistrar, - IMainDom mainDom, - ICoreScopeProvider scopeProvider, - ILogger logger, - IProfilingLogger profilingLogger, - ICronTabParser cronTabParser) - : base( - logger, - healthChecksSettings.CurrentValue.Notification.Period, - GetDelay(healthChecksSettings.CurrentValue.Notification.FirstRunTime, cronTabParser, logger, DefaultDelay)) - { - _healthChecksSettings = healthChecksSettings.CurrentValue; - _healthChecks = healthChecks; - _notifications = notifications; - _runtimeState = runtimeState; - _serverRegistrar = serverRegistrar; - _mainDom = mainDom; - _scopeProvider = scopeProvider; - _logger = logger; - _profilingLogger = profilingLogger; - - healthChecksSettings.OnChange(x => - { - _healthChecksSettings = x; - ChangePeriod(x.Notification.Period); - }); - } - - public override async Task PerformExecuteAsync(object? state) - { - if (_healthChecksSettings.Notification.Enabled == false) - { - return; - } - - if (_runtimeState.Level != RuntimeLevel.Run) - { - return; - } - - switch (_serverRegistrar.CurrentServerRole) - { - case ServerRole.Subscriber: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on subscriber servers."); - } - return; - case ServerRole.Unknown: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on servers with unknown role."); - } - return; - } - - // Ensure we do not run if not main domain, but do NOT lock it - if (_mainDom.IsMainDom == false) - { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run if not MainDom."); - } - return; - } - - // Ensure we use an explicit scope since we are running on a background thread and plugin health - // checks can be making service/database calls so we want to ensure the CallContext/Ambient scope - // isn't used since that can be problematic. - using (ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true)) - using (!_profilingLogger.IsEnabled(Core.Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration("Health checks executing", "Health checks complete")) - { - // Don't notify for any checks that are disabled, nor for any disabled just for notifications. - Guid[] disabledCheckIds = _healthChecksSettings.Notification.DisabledChecks - .Select(x => x.Id) - .Union(_healthChecksSettings.DisabledChecks - .Select(x => x.Id)) - .Distinct() - .ToArray(); - - IEnumerable checks = _healthChecks - .Where(x => disabledCheckIds.Contains(x.Id) == false); - - HealthCheckResults results = await HealthCheckResults.Create(checks); - results.LogResults(); - - // Send using registered notification methods that are enabled. - foreach (IHealthCheckNotificationMethod notificationMethod in _notifications.Where(x => x.Enabled)) - { - await notificationMethod.SendAsync(results); - } - } - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs b/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs deleted file mode 100644 index 978ffa2dd1..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/KeepAlive.cs +++ /dev/null @@ -1,119 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Routing; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Sync; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Infrastructure.HostedServices; - -/// -/// Hosted service implementation for keep alive feature. -/// -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.KeepAliveJob instead. This class will be removed in Umbraco 14.")] -public class KeepAlive : RecurringHostedServiceBase -{ - private readonly IHostingEnvironment _hostingEnvironment; - private readonly IHttpClientFactory _httpClientFactory; - private readonly ILogger _logger; - private readonly IMainDom _mainDom; - private readonly IProfilingLogger _profilingLogger; - private readonly IServerRoleAccessor _serverRegistrar; - private KeepAliveSettings _keepAliveSettings; - - /// - /// Initializes a new instance of the class. - /// - /// The current hosting environment - /// Representation of the main application domain. - /// The configuration for keep alive settings. - /// The typed logger. - /// The profiling logger. - /// Provider of server registrations to the distributed cache. - /// Factory for instances. - public KeepAlive( - IHostingEnvironment hostingEnvironment, - IMainDom mainDom, - IOptionsMonitor keepAliveSettings, - ILogger logger, - IProfilingLogger profilingLogger, - IServerRoleAccessor serverRegistrar, - IHttpClientFactory httpClientFactory) - : base(logger, TimeSpan.FromMinutes(5), DefaultDelay) - { - _hostingEnvironment = hostingEnvironment; - _mainDom = mainDom; - _keepAliveSettings = keepAliveSettings.CurrentValue; - _logger = logger; - _profilingLogger = profilingLogger; - _serverRegistrar = serverRegistrar; - _httpClientFactory = httpClientFactory; - - keepAliveSettings.OnChange(x => _keepAliveSettings = x); - } - - public override async Task PerformExecuteAsync(object? state) - { - if (_keepAliveSettings.DisableKeepAliveTask) - { - return; - } - - // Don't run on replicas nor unknown role servers - switch (_serverRegistrar.CurrentServerRole) - { - case ServerRole.Subscriber: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on subscriber servers."); - } - return; - case ServerRole.Unknown: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on servers with unknown role."); - } - return; - } - - // Ensure we do not run if not main domain, but do NOT lock it - if (_mainDom.IsMainDom == false) - { - _logger.LogDebug("Does not run if not MainDom."); - return; - } - - using (!_profilingLogger.IsEnabled(Core.Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration("Keep alive executing", "Keep alive complete")) - { - var umbracoAppUrl = _hostingEnvironment.ApplicationMainUrl?.ToString(); - if (umbracoAppUrl.IsNullOrWhiteSpace()) - { - _logger.LogWarning("No umbracoApplicationUrl for service (yet), skip."); - return; - } - - // If the config is an absolute path, just use it - var keepAlivePingUrl = WebPath.Combine( - umbracoAppUrl!, - _hostingEnvironment.ToAbsolute(_keepAliveSettings.KeepAlivePingUrl)); - - try - { - var request = new HttpRequestMessage(HttpMethod.Get, keepAlivePingUrl); - HttpClient httpClient = _httpClientFactory.CreateClient(Constants.HttpClients.IgnoreCertificateErrors); - _ = await httpClient.SendAsync(request); - } - catch (Exception ex) - { - _logger.LogError(ex, "Keep alive failed (at '{keepAlivePingUrl}').", keepAlivePingUrl); - } - } - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs b/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs deleted file mode 100644 index 4c3df658c6..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/LogScrubber.cs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; - -namespace Umbraco.Cms.Infrastructure.HostedServices; - -/// -/// Log scrubbing hosted service. -/// -/// -/// Will only run on non-replica servers. -/// -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.LogScrubberJob instead. This class will be removed in Umbraco 14.")] -public class LogScrubber : RecurringHostedServiceBase -{ - private readonly IAuditService _auditService; - private readonly ILogger _logger; - private readonly IMainDom _mainDom; - private readonly IProfilingLogger _profilingLogger; - private readonly ICoreScopeProvider _scopeProvider; - private readonly IServerRoleAccessor _serverRegistrar; - private LoggingSettings _settings; - - /// - /// Initializes a new instance of the class. - /// - /// Representation of the main application domain. - /// Provider of server registrations to the distributed cache. - /// Service for handling audit operations. - /// The configuration for logging settings. - /// Provides scopes for database operations. - /// The typed logger. - /// The profiling logger. - public LogScrubber( - IMainDom mainDom, - IServerRoleAccessor serverRegistrar, - IAuditService auditService, - IOptionsMonitor settings, - ICoreScopeProvider scopeProvider, - ILogger logger, - IProfilingLogger profilingLogger) - : base(logger, TimeSpan.FromHours(4), DefaultDelay) - { - _mainDom = mainDom; - _serverRegistrar = serverRegistrar; - _auditService = auditService; - _settings = settings.CurrentValue; - _scopeProvider = scopeProvider; - _logger = logger; - _profilingLogger = profilingLogger; - settings.OnChange(x => _settings = x); - } - - public override Task PerformExecuteAsync(object? state) - { - switch (_serverRegistrar.CurrentServerRole) - { - case ServerRole.Subscriber: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on subscriber servers."); - } - return Task.CompletedTask; - case ServerRole.Unknown: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on servers with unknown role."); - } - return Task.CompletedTask; - } - - // Ensure we do not run if not main domain, but do NOT lock it - if (_mainDom.IsMainDom == false) - { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run if not MainDom."); - } - return Task.CompletedTask; - } - - // Ensure we use an explicit scope since we are running on a background thread. - using (ICoreScope scope = _scopeProvider.CreateCoreScope()) - using (!_profilingLogger.IsEnabled(Core.Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration("Log scrubbing executing", "Log scrubbing complete")) - { - _auditService.CleanLogs((int)_settings.MaxLogAge.TotalMinutes); - _ = scope.Complete(); - } - - return Task.CompletedTask; - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs b/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs deleted file mode 100644 index a0eb8cfb89..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/ReportSiteTask.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Text; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Telemetry; -using Umbraco.Cms.Core.Telemetry.Models; - -namespace Umbraco.Cms.Infrastructure.HostedServices; - -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.ReportSiteJob instead. This class will be removed in Umbraco 14.")] -public class ReportSiteTask : RecurringHostedServiceBase -{ - private static HttpClient _httpClient = new(); - private readonly ILogger _logger; - private readonly ITelemetryService _telemetryService; - private readonly IRuntimeState _runtimeState; - - public ReportSiteTask( - ILogger logger, - ITelemetryService telemetryService, - IRuntimeState runtimeState) - : base(logger, TimeSpan.FromDays(1), TimeSpan.FromMinutes(5)) - { - _logger = logger; - _telemetryService = telemetryService; - _runtimeState = runtimeState; - _httpClient = new HttpClient(); - } - - [Obsolete("Use the constructor that takes IRuntimeState, scheduled for removal in V12")] - public ReportSiteTask( - ILogger logger, - ITelemetryService telemetryService) - : this(logger, telemetryService, StaticServiceProvider.Instance.GetRequiredService()) - { - } - - /// - /// Runs the background task to send the anonymous ID - /// to telemetry service - /// - public override async Task PerformExecuteAsync(object? state) - { - if (_runtimeState.Level is not RuntimeLevel.Run) - { - // We probably haven't installed yet, so we can't get telemetry. - return; - } - - TelemetryReportData? telemetryReportData = await _telemetryService.GetTelemetryReportDataAsync(); - if (telemetryReportData is null) - { - _logger.LogWarning("No telemetry marker found"); - - return; - } - - try - { - if (_httpClient.BaseAddress is null) - { - // Send data to LIVE telemetry - _httpClient.BaseAddress = new Uri("https://telemetry.umbraco.com/"); - -#if DEBUG - // Send data to DEBUG telemetry service - _httpClient.BaseAddress = new Uri("https://telemetry.rainbowsrock.net/"); -#endif - } - - _httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); - - using (var request = new HttpRequestMessage(HttpMethod.Post, "installs/")) - { - request.Content = new StringContent(JsonConvert.SerializeObject(telemetryReportData), Encoding.UTF8, - "application/json"); - - // Make a HTTP Post to telemetry service - // https://telemetry.umbraco.com/installs/ - // Fire & Forget, do not need to know if its a 200, 500 etc - using (await _httpClient.SendAsync(request)) - { - } - } - } - catch - { - // Silently swallow - // The user does not need the logs being polluted if our service has fallen over or is down etc - // Hence only logging this at a more verbose level (which users should not be using in production) - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("There was a problem sending a request to the Umbraco telemetry service"); - } - } - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs b/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs deleted file mode 100644 index efbd8017df..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/ScheduledPublishing.cs +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Core.Web; - -namespace Umbraco.Cms.Infrastructure.HostedServices; - -/// -/// Hosted service implementation for scheduled publishing feature. -/// -/// -/// Runs only on non-replica servers. -/// -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.ScheduledPublishingJob instead. This class will be removed in Umbraco 14.")] -public class ScheduledPublishing : RecurringHostedServiceBase -{ - private readonly IContentService _contentService; - private readonly ILogger _logger; - private readonly IMainDom _mainDom; - private readonly IRuntimeState _runtimeState; - private readonly ICoreScopeProvider _scopeProvider; - private readonly IServerMessenger _serverMessenger; - private readonly IServerRoleAccessor _serverRegistrar; - private readonly IUmbracoContextFactory _umbracoContextFactory; - - /// - /// Initializes a new instance of the class. - /// - public ScheduledPublishing( - IRuntimeState runtimeState, - IMainDom mainDom, - IServerRoleAccessor serverRegistrar, - IContentService contentService, - IUmbracoContextFactory umbracoContextFactory, - ILogger logger, - IServerMessenger serverMessenger, - ICoreScopeProvider scopeProvider) - : base(logger, TimeSpan.FromMinutes(1), DefaultDelay) - { - _runtimeState = runtimeState; - _mainDom = mainDom; - _serverRegistrar = serverRegistrar; - _contentService = contentService; - _umbracoContextFactory = umbracoContextFactory; - _logger = logger; - _serverMessenger = serverMessenger; - _scopeProvider = scopeProvider; - } - - public override Task PerformExecuteAsync(object? state) - { - if (Suspendable.ScheduledPublishing.CanRun == false) - { - return Task.CompletedTask; - } - - switch (_serverRegistrar.CurrentServerRole) - { - case ServerRole.Subscriber: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on subscriber servers."); - } - return Task.CompletedTask; - case ServerRole.Unknown: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run on servers with unknown role."); - } - return Task.CompletedTask; - } - - // Ensure we do not run if not main domain, but do NOT lock it - if (_mainDom.IsMainDom == false) - { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run if not MainDom."); - } - return Task.CompletedTask; - } - - // Do NOT run publishing if not properly running - if (_runtimeState.Level != RuntimeLevel.Run) - { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run if run level is not Run."); - } - return Task.CompletedTask; - } - - try - { - // Ensure we run with an UmbracoContext, because this will run in a background task, - // and developers may be using the UmbracoContext in the event handlers. - - // TODO: or maybe not, CacheRefresherComponent already ensures a context when handling events - // - UmbracoContext 'current' needs to be refactored and cleaned up - // - batched messenger should not depend on a current HttpContext - // but then what should be its "scope"? could we attach it to scopes? - // - and we should definitively *not* have to flush it here (should be auto) - using UmbracoContextReference contextReference = _umbracoContextFactory.EnsureUmbracoContext(); - using ICoreScope scope = _scopeProvider.CreateCoreScope(); - - /* We used to assume that there will never be two instances running concurrently where (IsMainDom && ServerRole == SchedulingPublisher) - * However this is possible during an azure deployment slot swap for the SchedulingPublisher instance when trying to achieve zero downtime deployments. - * If we take a distributed write lock, we are certain that the multiple instances of the job will not run in parallel. - * It's possible that during the swapping process we may run this job more frequently than intended but this is not of great concern and it's - * only until the old SchedulingPublisher shuts down. */ - scope.EagerWriteLock(Constants.Locks.ScheduledPublishing); - try - { - // Run - IEnumerable result = _contentService.PerformScheduledPublish(DateTime.Now); - foreach (IGrouping grouped in result.GroupBy(x => x.Result)) - { - _logger.LogInformation( - "Scheduled publishing result: '{StatusCount}' items with status {Status}", - grouped.Count(), - grouped.Key); - } - - scope.Complete(); - } - finally - { - // If running on a temp context, we have to flush the messenger - if (contextReference.IsRoot) - { - _serverMessenger.SendMessages(); - } - } - } - catch (Exception ex) - { - // important to catch *everything* to ensure the task repeats - _logger.LogError(ex, "Failed."); - } - - return Task.CompletedTask; - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs deleted file mode 100644 index fbbdab8878..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTask.cs +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; - -namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration; - -/// -/// Implements periodic database instruction processing as a hosted service. -/// -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.ServerRegistration.InstructionProcessJob instead. This class will be removed in Umbraco 14.")] -public class InstructionProcessTask : RecurringHostedServiceBase -{ - private readonly ILogger _logger; - private readonly IServerMessenger _messenger; - private readonly IRuntimeState _runtimeState; - private bool _disposedValue; - - /// - /// Initializes a new instance of the class. - /// - /// Representation of the state of the Umbraco runtime. - /// Service broadcasting cache notifications to registered servers. - /// The typed logger. - /// The configuration for global settings. - public InstructionProcessTask(IRuntimeState runtimeState, IServerMessenger messenger, ILogger logger, IOptions globalSettings) - : base(logger, globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1)) - { - _runtimeState = runtimeState; - _messenger = messenger; - _logger = logger; - } - - public override Task PerformExecuteAsync(object? state) - { - if (_runtimeState.Level != RuntimeLevel.Run) - { - return Task.CompletedTask; - } - - try - { - _messenger.Sync(); - } - catch (Exception e) - { - _logger.LogError(e, "Failed (will repeat)."); - } - - return Task.CompletedTask; - } - - protected override void Dispose(bool disposing) - { - if (!_disposedValue) - { - if (disposing && _messenger is IDisposable disposable) - { - disposable.Dispose(); - } - - _disposedValue = true; - } - - base.Dispose(disposing); - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs b/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs deleted file mode 100644 index a844c33ad6..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTask.cs +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Extensions; - -namespace Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration; - -/// -/// Implements periodic server "touching" (to mark as active/deactive) as a hosted service. -/// -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.ServerRegistration.TouchServerJob instead. This class will be removed in Umbraco 14.")] -public class TouchServerTask : RecurringHostedServiceBase -{ - private readonly IHostingEnvironment _hostingEnvironment; - private readonly ILogger _logger; - private readonly IRuntimeState _runtimeState; - private readonly IServerRegistrationService _serverRegistrationService; - private readonly IServerRoleAccessor _serverRoleAccessor; - private GlobalSettings _globalSettings; - - /// - /// Initializes a new instance of the class. - /// - /// Representation of the state of the Umbraco runtime. - /// Services for server registrations. - /// The typed logger. - /// The configuration for global settings. - /// The hostingEnviroment. - /// The accessor for the server role - public TouchServerTask( - IRuntimeState runtimeState, - IServerRegistrationService serverRegistrationService, - IHostingEnvironment hostingEnvironment, - ILogger logger, - IOptionsMonitor globalSettings, - IServerRoleAccessor serverRoleAccessor) - : base(logger, globalSettings.CurrentValue.DatabaseServerRegistrar.WaitTimeBetweenCalls, TimeSpan.FromSeconds(15)) - { - _runtimeState = runtimeState; - _serverRegistrationService = serverRegistrationService ?? - throw new ArgumentNullException(nameof(serverRegistrationService)); - _hostingEnvironment = hostingEnvironment; - _logger = logger; - _globalSettings = globalSettings.CurrentValue; - globalSettings.OnChange(x => - { - _globalSettings = x; - ChangePeriod(x.DatabaseServerRegistrar.WaitTimeBetweenCalls); - }); - _serverRoleAccessor = serverRoleAccessor; - } - - public override Task PerformExecuteAsync(object? state) - { - if (_runtimeState.Level != RuntimeLevel.Run) - { - return Task.CompletedTask; - } - - // If the IServerRoleAccessor has been changed away from ElectedServerRoleAccessor this task no longer makes sense, - // since all it's used for is to allow the ElectedServerRoleAccessor - // to figure out what role a given server has, so we just stop this task. - if (_serverRoleAccessor is not ElectedServerRoleAccessor) - { - return StopAsync(CancellationToken.None); - } - - var serverAddress = _hostingEnvironment.ApplicationMainUrl?.ToString(); - if (serverAddress.IsNullOrWhiteSpace()) - { - _logger.LogWarning("No umbracoApplicationUrl for service (yet), skip."); - return Task.CompletedTask; - } - - try - { - _serverRegistrationService.TouchServer( - serverAddress!, - _globalSettings.DatabaseServerRegistrar.StaleServerTimeout); - } - catch (Exception ex) - { - _logger.LogError(ex, "Failed to update server record in database."); - } - - return Task.CompletedTask; - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs b/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs deleted file mode 100644 index 81de651e79..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/TempFileCleanup.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Runtime; - -namespace Umbraco.Cms.Infrastructure.HostedServices; - -/// -/// Used to cleanup temporary file locations. -/// -/// -/// Will run on all servers - even though file upload should only be handled on the scheduling publisher, this will -/// ensure that in the case it happens on subscribers that they are cleaned up too. -/// -[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.TempFileCleanupJob instead. This class will be removed in Umbraco 14.")] -public class TempFileCleanup : RecurringHostedServiceBase -{ - private readonly TimeSpan _age = TimeSpan.FromDays(1); - private readonly IIOHelper _ioHelper; - private readonly ILogger _logger; - private readonly IMainDom _mainDom; - - private readonly DirectoryInfo[] _tempFolders; - - /// - /// Initializes a new instance of the class. - /// - /// Helper service for IO operations. - /// Representation of the main application domain. - /// The typed logger. - public TempFileCleanup(IIOHelper ioHelper, IMainDom mainDom, ILogger logger) - : base(logger, TimeSpan.FromMinutes(60), DefaultDelay) - { - _ioHelper = ioHelper; - _mainDom = mainDom; - _logger = logger; - - _tempFolders = _ioHelper.GetTempFolders(); - } - - public override Task PerformExecuteAsync(object? state) - { - // Ensure we do not run if not main domain - if (_mainDom.IsMainDom == false) - { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("Does not run if not MainDom."); - } - return Task.CompletedTask; - } - - foreach (DirectoryInfo folder in _tempFolders) - { - CleanupFolder(folder); - } - - return Task.CompletedTask; - } - - private void CleanupFolder(DirectoryInfo folder) - { - CleanFolderResult result = _ioHelper.CleanFolder(folder, _age); - switch (result.Status) - { - case CleanFolderResultStatus.FailedAsDoesNotExist: - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("The cleanup folder doesn't exist {Folder}", folder.FullName); - } - break; - case CleanFolderResultStatus.FailedWithException: - foreach (CleanFolderResult.Error error in result.Errors!) - { - _logger.LogError(error.Exception, "Could not delete temp file {FileName}", - error.ErroringFile.FullName); - } - - break; - } - - folder.Refresh(); // In case it's changed during runtime - if (!folder.Exists) - { - if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug)) - { - _logger.LogDebug("The cleanup folder doesn't exist {Folder}", folder.FullName); - } - return; - } - - FileInfo[] files = folder.GetFiles("*.*", SearchOption.AllDirectories); - foreach (FileInfo file in files) - { - if (DateTime.UtcNow - file.LastWriteTimeUtc > _age) - { - try - { - file.IsReadOnly = false; - file.Delete(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Could not delete temp file {FileName}", file.FullName); - } - } - } - } -} diff --git a/src/Umbraco.Infrastructure/HostedServices/TemporaryFileCleanup.cs b/src/Umbraco.Infrastructure/HostedServices/TemporaryFileCleanup.cs deleted file mode 100644 index bacc72609e..0000000000 --- a/src/Umbraco.Infrastructure/HostedServices/TemporaryFileCleanup.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; - -namespace Umbraco.Cms.Infrastructure.HostedServices; - -/// -/// Recurring hosted service that executes the temporary file cleanup. -/// -public class TemporaryFileCleanup : RecurringHostedServiceBase -{ - private readonly ILogger _logger; - private readonly IMainDom _mainDom; - private readonly IRuntimeState _runtimeState; - private readonly IServerRoleAccessor _serverRoleAccessor; - private readonly ITemporaryFileService _service; - - /// - /// Initializes a new instance of the class. - /// - public TemporaryFileCleanup( - IRuntimeState runtimeState, - ILogger logger, - ITemporaryFileService temporaryFileService, - IMainDom mainDom, - IServerRoleAccessor serverRoleAccessor) - : base(logger, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5)) - { - _runtimeState = runtimeState; - _logger = logger; - _service = temporaryFileService; - _mainDom = mainDom; - _serverRoleAccessor = serverRoleAccessor; - } - - /// - public override Task PerformExecuteAsync(object? state) - { - if (_runtimeState.Level != RuntimeLevel.Run) - { - return Task.FromResult(true); // repeat... - } - - // Don't run on replicas nor unknown role servers - switch (_serverRoleAccessor.CurrentServerRole) - { - case ServerRole.Subscriber: - _logger.LogDebug("Does not run on subscriber servers"); - return Task.CompletedTask; - case ServerRole.Unknown: - _logger.LogDebug("Does not run on servers with unknown role"); - return Task.CompletedTask; - case ServerRole.Single: - case ServerRole.SchedulingPublisher: - default: - break; - } - - // Ensure we do not run if not main domain, but do NOT lock it - if (!_mainDom.IsMainDom) - { - _logger.LogDebug("Does not run if not MainDom"); - return Task.FromResult(false); // do NOT repeat, going down - } - - var count = _service.CleanUpOldTempFiles().GetAwaiter().GetResult().Count(); - - if (count > 0) - { - _logger.LogDebug("Deleted {Count} temporary file(s)", count); - } - else - { - _logger.LogDebug("Task complete, no items were deleted"); - } - - return Task.FromResult(true); - } -} diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index c93f986b36..1aadbd4526 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -46,7 +46,6 @@ using Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs; using Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs.ServerRegistration; using Umbraco.Cms.Infrastructure.DependencyInjection; using Umbraco.Cms.Infrastructure.HostedServices; -using Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration; using Umbraco.Cms.Infrastructure.Migrations.Install; using Umbraco.Cms.Infrastructure.Persistence; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; @@ -181,31 +180,6 @@ public static partial class UmbracoBuilderExtensions return builder; } - /// - /// Add Umbraco hosted services - /// - [Obsolete("Use AddRecurringBackgroundJobs instead")] - public static IUmbracoBuilder AddHostedServices(this IUmbracoBuilder builder) - { - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(); - builder.Services.AddHostedService(provider => - new ReportSiteTask( - provider.GetRequiredService>(), - provider.GetRequiredService())); - - - return builder; - } - /// /// Add Umbraco recurring background jobs /// @@ -218,19 +192,17 @@ public static partial class UmbracoBuilderExtensions builder.Services.AddRecurringBackgroundJob(); builder.Services.AddRecurringBackgroundJob(); builder.Services.AddRecurringBackgroundJob(); + builder.Services.AddRecurringBackgroundJob(); builder.Services.AddRecurringBackgroundJob(); builder.Services.AddRecurringBackgroundJob(); builder.Services.AddRecurringBackgroundJob(); builder.Services.AddRecurringBackgroundJob(); - builder.Services.AddRecurringBackgroundJob(provider => - new ReportSiteJob( - provider.GetRequiredService>(), - provider.GetRequiredService())); + builder.Services.AddRecurringBackgroundJob(); - builder.Services.AddHostedService(); builder.Services.AddSingleton(RecurringBackgroundJobHostedService.CreateHostedServiceFactory); builder.Services.AddHostedService(); + builder.Services.AddHostedService(); return builder; } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Scheduling/ContentVersionCleanupTest.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Scheduling/ContentVersionCleanupTest.cs index 6f2d1af7e4..35bd9e3450 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Scheduling/ContentVersionCleanupTest.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Scheduling/ContentVersionCleanupTest.cs @@ -8,6 +8,7 @@ using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Sync; +using Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs; using Umbraco.Cms.Infrastructure.HostedServices; using Umbraco.Cms.Tests.UnitTests.AutoFixture; @@ -24,7 +25,7 @@ internal class ContentVersionCleanupTest [Frozen] Mock serverRoleAccessor, [Frozen] Mock runtimeState, [Frozen] Mock cleanupService, - ContentVersionCleanup sut) + ContentVersionCleanupJob sut) { settings.Setup(x => x.CurrentValue).Returns(new ContentSettings { @@ -34,77 +35,7 @@ internal class ContentVersionCleanupTest mainDom.Setup(x => x.IsMainDom).Returns(true); serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.SchedulingPublisher); - await sut.PerformExecuteAsync(null); - - cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny()), Times.Never); - } - - [Test] - [AutoMoqData] - public async Task ContentVersionCleanup_RuntimeLevelNotRun_DoesNotCleanupWillRepeat( - [Frozen] Mock> settings, - [Frozen] Mock mainDom, - [Frozen] Mock serverRoleAccessor, - [Frozen] Mock runtimeState, - [Frozen] Mock cleanupService, - ContentVersionCleanup sut) - { - settings.Setup(x => x.CurrentValue).Returns(new ContentSettings - { - ContentVersionCleanupPolicy = new ContentVersionCleanupPolicySettings { EnableCleanup = true }, - }); - runtimeState.Setup(x => x.Level).Returns(RuntimeLevel.Unknown); - mainDom.Setup(x => x.IsMainDom).Returns(true); - serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.SchedulingPublisher); - - await sut.PerformExecuteAsync(null); - - cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny()), Times.Never); - } - - [Test] - [AutoMoqData] - public async Task ContentVersionCleanup_ServerRoleUnknown_DoesNotCleanupWillRepeat( - [Frozen] Mock> settings, - [Frozen] Mock mainDom, - [Frozen] Mock serverRoleAccessor, - [Frozen] Mock runtimeState, - [Frozen] Mock cleanupService, - ContentVersionCleanup sut) - { - settings.Setup(x => x.CurrentValue).Returns(new ContentSettings - { - ContentVersionCleanupPolicy = new ContentVersionCleanupPolicySettings { EnableCleanup = true }, - }); - runtimeState.Setup(x => x.Level).Returns(RuntimeLevel.Run); - mainDom.Setup(x => x.IsMainDom).Returns(true); - serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.Unknown); - - await sut.PerformExecuteAsync(null); - - cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny()), Times.Never); - } - - [Test] - [AutoMoqData] - public async Task ContentVersionCleanup_NotMainDom_DoesNotCleanupWillNotRepeat( - [Frozen] Mock> settings, - [Frozen] Mock mainDom, - [Frozen] Mock serverRoleAccessor, - [Frozen] Mock runtimeState, - [Frozen] Mock cleanupService, - ContentVersionCleanup sut) - { - settings.Setup(x => x.CurrentValue).Returns(new ContentSettings - { - ContentVersionCleanupPolicy = new ContentVersionCleanupPolicySettings { EnableCleanup = true }, - }); - - runtimeState.Setup(x => x.Level).Returns(RuntimeLevel.Run); - mainDom.Setup(x => x.IsMainDom).Returns(false); - serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.SchedulingPublisher); - - await sut.PerformExecuteAsync(null); + await sut.RunJobAsync(); cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny()), Times.Never); } @@ -117,7 +48,7 @@ internal class ContentVersionCleanupTest [Frozen] Mock serverRoleAccessor, [Frozen] Mock runtimeState, [Frozen] Mock cleanupService, - ContentVersionCleanup sut) + ContentVersionCleanupJob sut) { settings.Setup(x => x.CurrentValue).Returns(new ContentSettings { @@ -128,7 +59,7 @@ internal class ContentVersionCleanupTest mainDom.Setup(x => x.IsMainDom).Returns(true); serverRoleAccessor.Setup(x => x.CurrentServerRole).Returns(ServerRole.SchedulingPublisher); - await sut.PerformExecuteAsync(null); + await sut.RunJobAsync(); cleanupService.Verify(x => x.PerformContentVersionCleanup(It.IsAny()), Times.Once); } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackgroundJobs/Jobs/ServerRegistration/TouchServerJobTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackgroundJobs/Jobs/ServerRegistration/TouchServerJobTests.cs index 0da3b15e1b..8bbecb26fc 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackgroundJobs/Jobs/ServerRegistration/TouchServerJobTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackgroundJobs/Jobs/ServerRegistration/TouchServerJobTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Umbraco. // See LICENSE for more details. -using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Moq; using NUnit.Framework; @@ -11,7 +10,6 @@ using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Sync; using Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs.ServerRegistration; -using Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration; using Umbraco.Cms.Tests.Common; namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.BackgroundJobs.Jobs.ServerRegistration; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs deleted file mode 100644 index 03d7f344a6..0000000000 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/HealthCheckNotifierTests.cs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.HealthChecks; -using Umbraco.Cms.Core.HealthChecks.NotificationMethods; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Infrastructure.HostedServices; -using Umbraco.Cms.Infrastructure.Scoping; -using Umbraco.Cms.Tests.Common; - -namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices; - -[TestFixture] -[Obsolete("Replaced by BackgroundJobs.Jobs.HealthCheckNotifierJobTests")] -public class HealthCheckNotifierTests -{ - private Mock _mockNotificationMethod; - - private const string Check1Id = "00000000-0000-0000-0000-000000000001"; - private const string Check2Id = "00000000-0000-0000-0000-000000000002"; - private const string Check3Id = "00000000-0000-0000-0000-000000000003"; - - [Test] - public async Task Does_Not_Execute_When_Not_Enabled() - { - var sut = CreateHealthCheckNotifier(false); - await sut.PerformExecuteAsync(null); - VerifyNotificationsNotSent(); - } - - [TestCase(RuntimeLevel.Boot)] - [TestCase(RuntimeLevel.Install)] - [TestCase(RuntimeLevel.Unknown)] - [TestCase(RuntimeLevel.Upgrade)] - [TestCase(RuntimeLevel.BootFailed)] - public async Task Does_Not_Execute_When_Runtime_State_Is_Not_Run(RuntimeLevel runtimeLevel) - { - var sut = CreateHealthCheckNotifier(runtimeLevel: runtimeLevel); - await sut.PerformExecuteAsync(null); - VerifyNotificationsNotSent(); - } - - [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() - { - var sut = CreateHealthCheckNotifier(serverRole: ServerRole.Subscriber); - await sut.PerformExecuteAsync(null); - VerifyNotificationsNotSent(); - } - - [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Unknown() - { - var sut = CreateHealthCheckNotifier(serverRole: ServerRole.Unknown); - await sut.PerformExecuteAsync(null); - VerifyNotificationsNotSent(); - } - - [Test] - public async Task Does_Not_Execute_When_Not_Main_Dom() - { - var sut = CreateHealthCheckNotifier(isMainDom: false); - await sut.PerformExecuteAsync(null); - VerifyNotificationsNotSent(); - } - - [Test] - public async Task Does_Not_Execute_With_No_Enabled_Notification_Methods() - { - var sut = CreateHealthCheckNotifier(notificationEnabled: false); - await sut.PerformExecuteAsync(null); - VerifyNotificationsNotSent(); - } - - [Test] - public async Task Executes_With_Enabled_Notification_Methods() - { - var sut = CreateHealthCheckNotifier(); - await sut.PerformExecuteAsync(null); - VerifyNotificationsSent(); - } - - [Test] - public async Task Executes_Only_Enabled_Checks() - { - var sut = CreateHealthCheckNotifier(); - await sut.PerformExecuteAsync(null); - _mockNotificationMethod.Verify( - x => x.SendAsync( - It.Is(y => - y.ResultsAsDictionary.Count == 1 && y.ResultsAsDictionary.ContainsKey("Check1"))), - Times.Once); - } - - private HealthCheckNotifier CreateHealthCheckNotifier( - bool enabled = true, - RuntimeLevel runtimeLevel = RuntimeLevel.Run, - ServerRole serverRole = ServerRole.Single, - bool isMainDom = true, - bool notificationEnabled = true) - { - var settings = new HealthChecksSettings - { - Notification = new HealthChecksNotificationSettings - { - Enabled = enabled, - DisabledChecks = new List { new() { Id = Guid.Parse(Check3Id) } }, - }, - DisabledChecks = new List { new() { Id = Guid.Parse(Check2Id) } }, - }; - var checks = new HealthCheckCollection(() => new List - { - new TestHealthCheck1(), - new TestHealthCheck2(), - new TestHealthCheck3(), - }); - - _mockNotificationMethod = new Mock(); - _mockNotificationMethod.SetupGet(x => x.Enabled).Returns(notificationEnabled); - var notifications = new HealthCheckNotificationMethodCollection(() => - new List { _mockNotificationMethod.Object }); - - var mockRunTimeState = new Mock(); - mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel); - - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); - - var mockMainDom = new Mock(); - mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); - - var mockScopeProvider = new Mock(); - var mockLogger = new Mock>(); - var mockProfilingLogger = new Mock(); - - return new HealthCheckNotifier( - new TestOptionsMonitor(settings), - checks, - notifications, - mockRunTimeState.Object, - mockServerRegistrar.Object, - mockMainDom.Object, - mockScopeProvider.Object, - mockLogger.Object, - mockProfilingLogger.Object, - Mock.Of()); - } - - private void VerifyNotificationsNotSent() => VerifyNotificationsSentTimes(Times.Never()); - - private void VerifyNotificationsSent() => VerifyNotificationsSentTimes(Times.Once()); - - private void VerifyNotificationsSentTimes(Times times) => - _mockNotificationMethod.Verify(x => x.SendAsync(It.IsAny()), times); - - [HealthCheck(Check1Id, "Check1")] - private class TestHealthCheck1 : TestHealthCheck - { - } - - [HealthCheck(Check2Id, "Check2")] - private class TestHealthCheck2 : TestHealthCheck - { - } - - [HealthCheck(Check3Id, "Check3")] - private class TestHealthCheck3 : TestHealthCheck - { - } - - private class TestHealthCheck : HealthCheck - { - public override HealthCheckStatus ExecuteAction(HealthCheckAction action) => new("Check message"); - - public override async Task> GetStatus() => Enumerable.Empty(); - } -} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs deleted file mode 100644 index 4631bb21a1..0000000000 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/KeepAliveTests.cs +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.Net; -using System.Net.Http; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Moq; -using Moq.Protected; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Infrastructure.HostedServices; -using Umbraco.Cms.Tests.Common; - -namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices; - -[TestFixture] -[Obsolete("Replaced by BackgroundJobs.Jobs.KeepAliveJobTests")] -public class KeepAliveTests -{ - private Mock _mockHttpMessageHandler; - - private const string ApplicationUrl = "https://mysite.com"; - - [Test] - public async Task Does_Not_Execute_When_Not_Enabled() - { - var sut = CreateKeepAlive(false); - await sut.PerformExecuteAsync(null); - VerifyKeepAliveRequestNotSent(); - } - - [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() - { - var sut = CreateKeepAlive(serverRole: ServerRole.Subscriber); - await sut.PerformExecuteAsync(null); - VerifyKeepAliveRequestNotSent(); - } - - [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Unknown() - { - var sut = CreateKeepAlive(serverRole: ServerRole.Unknown); - await sut.PerformExecuteAsync(null); - VerifyKeepAliveRequestNotSent(); - } - - [Test] - public async Task Does_Not_Execute_When_Not_Main_Dom() - { - var sut = CreateKeepAlive(isMainDom: false); - await sut.PerformExecuteAsync(null); - VerifyKeepAliveRequestNotSent(); - } - - [Test] - public async Task Executes_And_Calls_Ping_Url() - { - var sut = CreateKeepAlive(); - await sut.PerformExecuteAsync(null); - VerifyKeepAliveRequestSent(); - } - - private KeepAlive CreateKeepAlive( - bool enabled = true, - ServerRole serverRole = ServerRole.Single, - bool isMainDom = true) - { - var settings = new KeepAliveSettings { DisableKeepAliveTask = !enabled }; - - var mockHostingEnvironment = new Mock(); - mockHostingEnvironment.SetupGet(x => x.ApplicationMainUrl).Returns(new Uri(ApplicationUrl)); - mockHostingEnvironment.Setup(x => x.ToAbsolute(It.IsAny())) - .Returns((string s) => s.TrimStart('~')); - - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); - - var mockMainDom = new Mock(); - mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); - - var mockScopeProvider = new Mock(); - var mockLogger = new Mock>(); - var mockProfilingLogger = new Mock(); - - _mockHttpMessageHandler = new Mock(); - _mockHttpMessageHandler.Protected() - .Setup>( - "SendAsync", - ItExpr.IsAny(), - ItExpr.IsAny()) - .ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK)) - .Verifiable(); - _mockHttpMessageHandler.As().Setup(s => s.Dispose()); - var httpClient = new HttpClient(_mockHttpMessageHandler.Object); - - var mockHttpClientFactory = new Mock(MockBehavior.Strict); - mockHttpClientFactory.Setup(x => x.CreateClient(It.IsAny())).Returns(httpClient); - - return new KeepAlive( - mockHostingEnvironment.Object, - mockMainDom.Object, - new TestOptionsMonitor(settings), - mockLogger.Object, - mockProfilingLogger.Object, - mockServerRegistrar.Object, - mockHttpClientFactory.Object); - } - - private void VerifyKeepAliveRequestNotSent() => VerifyKeepAliveRequestSentTimes(Times.Never()); - - private void VerifyKeepAliveRequestSent() => VerifyKeepAliveRequestSentTimes(Times.Once()); - - private void VerifyKeepAliveRequestSentTimes(Times times) => _mockHttpMessageHandler.Protected() - .Verify( - "SendAsync", - times, - ItExpr.Is(x => x.RequestUri.ToString() == $"{ApplicationUrl}/api/keepalive/ping"), - ItExpr.IsAny()); -} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs deleted file mode 100644 index 98fdf4c453..0000000000 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/LogScrubberTests.cs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.Data; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Logging; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Infrastructure.HostedServices; -using Umbraco.Cms.Tests.Common; - -namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices; - -[TestFixture] -[Obsolete("Replaced by BackgroundJobs.Jobs.LogScrubberJobTests")] -public class LogScrubberTests -{ - private Mock _mockAuditService; - - private const int MaxLogAgeInMinutes = 60; - - [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() - { - var sut = CreateLogScrubber(ServerRole.Subscriber); - await sut.PerformExecuteAsync(null); - VerifyLogsNotScrubbed(); - } - - [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Unknown() - { - var sut = CreateLogScrubber(ServerRole.Unknown); - await sut.PerformExecuteAsync(null); - VerifyLogsNotScrubbed(); - } - - [Test] - public async Task Does_Not_Execute_When_Not_Main_Dom() - { - var sut = CreateLogScrubber(isMainDom: false); - await sut.PerformExecuteAsync(null); - VerifyLogsNotScrubbed(); - } - - [Test] - public async Task Executes_And_Scrubs_Logs() - { - var sut = CreateLogScrubber(); - await sut.PerformExecuteAsync(null); - VerifyLogsScrubbed(); - } - - private LogScrubber CreateLogScrubber( - ServerRole serverRole = ServerRole.Single, - bool isMainDom = true) - { - var settings = new LoggingSettings { MaxLogAge = TimeSpan.FromMinutes(MaxLogAgeInMinutes) }; - - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); - - var mockMainDom = new Mock(); - mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); - - var mockScope = new Mock(); - var mockScopeProvider = new Mock(); - mockScopeProvider - .Setup(x => x.CreateCoreScope( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Returns(mockScope.Object); - var mockLogger = new Mock>(); - var mockProfilingLogger = new Mock(); - - _mockAuditService = new Mock(); - - return new LogScrubber( - mockMainDom.Object, - mockServerRegistrar.Object, - _mockAuditService.Object, - new TestOptionsMonitor(settings), - mockScopeProvider.Object, - mockLogger.Object, - mockProfilingLogger.Object); - } - - private void VerifyLogsNotScrubbed() => VerifyLogsScrubbed(Times.Never()); - - private void VerifyLogsScrubbed() => VerifyLogsScrubbed(Times.Once()); - - private void VerifyLogsScrubbed(Times times) => - _mockAuditService.Verify(x => x.CleanLogs(It.Is(y => y == MaxLogAgeInMinutes)), times); -} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs deleted file mode 100644 index 3eb7756d7f..0000000000 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ScheduledPublishingTests.cs +++ /dev/null @@ -1,143 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.Data; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Core.Scoping; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Core.Web; -using Umbraco.Cms.Infrastructure; -using Umbraco.Cms.Infrastructure.HostedServices; - -namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices; - -[TestFixture] -[Obsolete("Replaced by BackgroundJobs.Jobs.ScheduledPublishingJobTests")] -public class ScheduledPublishingTests -{ - private Mock _mockContentService; - private Mock> _mockLogger; - - [Test] - public async Task Does_Not_Execute_When_Not_Enabled() - { - var sut = CreateScheduledPublishing(false); - await sut.PerformExecuteAsync(null); - VerifyScheduledPublishingNotPerformed(); - } - - [TestCase(RuntimeLevel.Boot)] - [TestCase(RuntimeLevel.Install)] - [TestCase(RuntimeLevel.Unknown)] - [TestCase(RuntimeLevel.Upgrade)] - [TestCase(RuntimeLevel.BootFailed)] - public async Task Does_Not_Execute_When_Runtime_State_Is_Not_Run(RuntimeLevel runtimeLevel) - { - var sut = CreateScheduledPublishing(runtimeLevel: runtimeLevel); - await sut.PerformExecuteAsync(null); - VerifyScheduledPublishingNotPerformed(); - } - - [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Subscriber() - { - var sut = CreateScheduledPublishing(serverRole: ServerRole.Subscriber); - await sut.PerformExecuteAsync(null); - VerifyScheduledPublishingNotPerformed(); - } - - [Test] - public async Task Does_Not_Execute_When_Server_Role_Is_Unknown() - { - var sut = CreateScheduledPublishing(serverRole: ServerRole.Unknown); - await sut.PerformExecuteAsync(null); - VerifyScheduledPublishingNotPerformed(); - } - - [Test] - public async Task Does_Not_Execute_When_Not_Main_Dom() - { - var sut = CreateScheduledPublishing(isMainDom: false); - await sut.PerformExecuteAsync(null); - VerifyScheduledPublishingNotPerformed(); - } - - [Test] - public async Task Executes_And_Performs_Scheduled_Publishing() - { - var sut = CreateScheduledPublishing(); - await sut.PerformExecuteAsync(null); - VerifyScheduledPublishingPerformed(); - } - - private ScheduledPublishing CreateScheduledPublishing( - bool enabled = true, - RuntimeLevel runtimeLevel = RuntimeLevel.Run, - ServerRole serverRole = ServerRole.Single, - bool isMainDom = true) - { - if (enabled) - { - Suspendable.ScheduledPublishing.Resume(); - } - else - { - Suspendable.ScheduledPublishing.Suspend(); - } - - var mockRunTimeState = new Mock(); - mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel); - - var mockServerRegistrar = new Mock(); - mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole); - - var mockMainDom = new Mock(); - mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); - - _mockContentService = new Mock(); - - var mockUmbracoContextFactory = new Mock(); - mockUmbracoContextFactory.Setup(x => x.EnsureUmbracoContext()) - .Returns(new UmbracoContextReference(null, false, null)); - - _mockLogger = new Mock>(); - - var mockServerMessenger = new Mock(); - - var mockScopeProvider = new Mock(); - mockScopeProvider - .Setup(x => x.CreateCoreScope( - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny(), - It.IsAny())) - .Returns(Mock.Of()); - - return new ScheduledPublishing( - mockRunTimeState.Object, - mockMainDom.Object, - mockServerRegistrar.Object, - _mockContentService.Object, - mockUmbracoContextFactory.Object, - _mockLogger.Object, - mockServerMessenger.Object, - mockScopeProvider.Object); - } - - private void VerifyScheduledPublishingNotPerformed() => VerifyScheduledPublishingPerformed(Times.Never()); - - private void VerifyScheduledPublishingPerformed() => VerifyScheduledPublishingPerformed(Times.Once()); - - private void VerifyScheduledPublishingPerformed(Times times) => - _mockContentService.Verify(x => x.PerformScheduledPublish(It.IsAny()), times); -} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs deleted file mode 100644 index 1513c6a5d4..0000000000 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/InstructionProcessTaskTests.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration; - -namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRegistration; - -[TestFixture] -[Obsolete("Replaced by BackgroundJobs.Jobs.ServerRegistration.InstructionProcessJobTests")] -public class InstructionProcessTaskTests -{ - private Mock _mockDatabaseServerMessenger; - - [TestCase(RuntimeLevel.Boot)] - [TestCase(RuntimeLevel.Install)] - [TestCase(RuntimeLevel.Unknown)] - [TestCase(RuntimeLevel.Upgrade)] - [TestCase(RuntimeLevel.BootFailed)] - public async Task Does_Not_Execute_When_Runtime_State_Is_Not_Run(RuntimeLevel runtimeLevel) - { - var sut = CreateInstructionProcessTask(runtimeLevel); - await sut.PerformExecuteAsync(null); - VerifyMessengerNotSynced(); - } - - [Test] - public async Task Executes_And_Touches_Server() - { - var sut = CreateInstructionProcessTask(); - await sut.PerformExecuteAsync(null); - VerifyMessengerSynced(); - } - - private InstructionProcessTask CreateInstructionProcessTask(RuntimeLevel runtimeLevel = RuntimeLevel.Run) - { - var mockRunTimeState = new Mock(); - mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel); - - var mockLogger = new Mock>(); - - _mockDatabaseServerMessenger = new Mock(); - - var settings = new GlobalSettings(); - - return new InstructionProcessTask( - mockRunTimeState.Object, - _mockDatabaseServerMessenger.Object, - mockLogger.Object, - Options.Create(settings)); - } - - private void VerifyMessengerNotSynced() => VerifyMessengerSyncedTimes(Times.Never()); - - private void VerifyMessengerSynced() => VerifyMessengerSyncedTimes(Times.Once()); - - private void VerifyMessengerSyncedTimes(Times times) => _mockDatabaseServerMessenger.Verify(x => x.Sync(), times); -} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs deleted file mode 100644 index 91d156e519..0000000000 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/ServerRegistration/TouchServerTaskTests.cs +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Sync; -using Umbraco.Cms.Infrastructure.HostedServices.ServerRegistration; -using Umbraco.Cms.Tests.Common; - -namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices.ServerRegistration; - -[TestFixture] -[Obsolete("Replaced by BackgroundJobs.Jobs.ServerRegistration.TouchServerJobTests")] -public class TouchServerTaskTests -{ - private Mock _mockServerRegistrationService; - - private const string ApplicationUrl = "https://mysite.com/"; - private readonly TimeSpan _staleServerTimeout = TimeSpan.FromMinutes(2); - - [TestCase(RuntimeLevel.Boot)] - [TestCase(RuntimeLevel.Install)] - [TestCase(RuntimeLevel.Unknown)] - [TestCase(RuntimeLevel.Upgrade)] - [TestCase(RuntimeLevel.BootFailed)] - public async Task Does_Not_Execute_When_Runtime_State_Is_Not_Run(RuntimeLevel runtimeLevel) - { - var sut = CreateTouchServerTask(runtimeLevel); - await sut.PerformExecuteAsync(null); - VerifyServerNotTouched(); - } - - [Test] - public async Task Does_Not_Execute_When_Application_Url_Is_Not_Available() - { - var sut = CreateTouchServerTask(applicationUrl: string.Empty); - await sut.PerformExecuteAsync(null); - VerifyServerNotTouched(); - } - - [Test] - public async Task Executes_And_Touches_Server() - { - var sut = CreateTouchServerTask(); - await sut.PerformExecuteAsync(null); - VerifyServerTouched(); - } - - [Test] - public async Task Does_Not_Execute_When_Role_Accessor_Is_Not_Elected() - { - var sut = CreateTouchServerTask(useElection: false); - await sut.PerformExecuteAsync(null); - VerifyServerNotTouched(); - } - - private TouchServerTask CreateTouchServerTask( - RuntimeLevel runtimeLevel = RuntimeLevel.Run, - string applicationUrl = ApplicationUrl, - bool useElection = true) - { - var mockRequestAccessor = new Mock(); - mockRequestAccessor.SetupGet(x => x.ApplicationMainUrl) - .Returns(!string.IsNullOrEmpty(applicationUrl) ? new Uri(ApplicationUrl) : null); - - var mockRunTimeState = new Mock(); - mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel); - - var mockLogger = new Mock>(); - - _mockServerRegistrationService = new Mock(); - - var settings = new GlobalSettings - { - DatabaseServerRegistrar = new DatabaseServerRegistrarSettings { StaleServerTimeout = _staleServerTimeout }, - }; - - IServerRoleAccessor roleAccessor = useElection - ? new ElectedServerRoleAccessor(_mockServerRegistrationService.Object) - : new SingleServerRoleAccessor(); - - return new TouchServerTask( - mockRunTimeState.Object, - _mockServerRegistrationService.Object, - mockRequestAccessor.Object, - mockLogger.Object, - new TestOptionsMonitor(settings), - roleAccessor); - } - - private void VerifyServerNotTouched() => VerifyServerTouchedTimes(Times.Never()); - - private void VerifyServerTouched() => VerifyServerTouchedTimes(Times.Once()); - - private void VerifyServerTouchedTimes(Times times) => _mockServerRegistrationService - .Verify( - x => x.TouchServer( - It.Is(y => y == ApplicationUrl), - It.Is(y => y == _staleServerTimeout)), - times); -} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/TempFileCleanupTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/TempFileCleanupTests.cs deleted file mode 100644 index 2128f917b9..0000000000 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/HostedServices/TempFileCleanupTests.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) Umbraco. -// See LICENSE for more details. - -using System.IO; -using System.Threading.Tasks; -using Microsoft.Extensions.Logging; -using Moq; -using NUnit.Framework; -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Runtime; -using Umbraco.Cms.Infrastructure.HostedServices; - -namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.HostedServices -{ - [TestFixture] - [Obsolete("Replaced by BackgroundJobs.Jobs.TempFileCleanupTests")] - public class TempFileCleanupTests - { - private Mock _mockIOHelper; - private readonly string _testPath = Path.Combine(TestContext.CurrentContext.TestDirectory.Split("bin")[0], "App_Data", "TEMP"); - - [Test] - public async Task Does_Not_Execute_When_Not_Main_Dom() - { - TempFileCleanup sut = CreateTempFileCleanup(isMainDom: false); - await sut.PerformExecuteAsync(null); - VerifyFilesNotCleaned(); - } - - [Test] - public async Task Executes_And_Cleans_Files() - { - TempFileCleanup sut = CreateTempFileCleanup(); - await sut.PerformExecuteAsync(null); - VerifyFilesCleaned(); - } - - private TempFileCleanup CreateTempFileCleanup(bool isMainDom = true) - { - var mockMainDom = new Mock(); - mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom); - - _mockIOHelper = new Mock(); - _mockIOHelper.Setup(x => x.GetTempFolders()) - .Returns(new DirectoryInfo[] { new(_testPath) }); - _mockIOHelper.Setup(x => x.CleanFolder(It.IsAny(), It.IsAny())) - .Returns(CleanFolderResult.Success()); - - var mockLogger = new Mock>(); - - return new TempFileCleanup(_mockIOHelper.Object, mockMainDom.Object, mockLogger.Object); - } - - private void VerifyFilesNotCleaned() => VerifyFilesCleaned(Times.Never()); - - private void VerifyFilesCleaned() => VerifyFilesCleaned(Times.Once()); - - private void VerifyFilesCleaned(Times times) => _mockIOHelper.Verify(x => x.CleanFolder(It.Is(y => y.FullName == _testPath), It.IsAny()), times); - } -}