Migrated ReportSite, OpenIddictCleanup and TemporaryFileCleanup to background jobs (#15555)
* Migrated ReportSite, OpenIddictCleanup and TemporaryFileCleanup to the new background jobs introduced in v13. * Fixed delay and period
This commit is contained in:
@@ -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<OpenIddictCleanup>();
|
||||
builder.Services.AddRecurringBackgroundJob<OpenIddictCleanupJob>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<OpenIddictCleanup> _logger;
|
||||
private readonly ILogger<OpenIddictCleanupJob> _logger;
|
||||
private readonly IServiceProvider _provider;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
|
||||
public OpenIddictCleanup(
|
||||
ILogger<OpenIddictCleanup> logger, IServiceProvider provider, IRuntimeState runtimeState)
|
||||
: base(logger, TimeSpan.FromHours(1), TimeSpan.FromMinutes(5))
|
||||
public OpenIddictCleanupJob(ILogger<OpenIddictCleanupJob> 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<IOpenIddictTokenManager>()
|
||||
?? 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<IOpenIddictAuthorizationManager>()
|
||||
?? 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)
|
||||
@@ -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<ReportSiteJob> _logger;
|
||||
private readonly ITelemetryService _telemetryService;
|
||||
|
||||
private readonly IJsonSerializer _jsonSerializer;
|
||||
|
||||
|
||||
public ReportSiteJob(
|
||||
ILogger<ReportSiteJob> 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
|
||||
|
||||
@@ -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<TemporaryFileCleanupJob> _logger;
|
||||
private readonly ITemporaryFileService _service;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TemporaryFileCleanupJob" /> class.
|
||||
/// </summary>
|
||||
public TemporaryFileCleanupJob(
|
||||
ILogger<TemporaryFileCleanupJob> logger,
|
||||
ITemporaryFileService temporaryFileService)
|
||||
{
|
||||
_logger = logger;
|
||||
_service = temporaryFileService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the background task to send the anonymous ID
|
||||
/// to telemetry service
|
||||
/// </summary>
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Recurring hosted service that executes the content history cleanup.
|
||||
/// </summary>
|
||||
[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.ContentVersionCleanupJob instead. This class will be removed in Umbraco 14.")]
|
||||
public class ContentVersionCleanup : RecurringHostedServiceBase
|
||||
{
|
||||
private readonly ILogger<ContentVersionCleanup> _logger;
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IServerRoleAccessor _serverRoleAccessor;
|
||||
private readonly IContentVersionService _service;
|
||||
private readonly IOptionsMonitor<ContentSettings> _settingsMonitor;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentVersionCleanup" /> class.
|
||||
/// </summary>
|
||||
public ContentVersionCleanup(
|
||||
IRuntimeState runtimeState,
|
||||
ILogger<ContentVersionCleanup> logger,
|
||||
IOptionsMonitor<ContentSettings> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Hosted service implementation for recurring health check notifications.
|
||||
/// </summary>
|
||||
[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<HealthCheckNotifier> _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;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HealthCheckNotifier" /> class.
|
||||
/// </summary>
|
||||
/// <param name="healthChecksSettings">The configuration for health check settings.</param>
|
||||
/// <param name="healthChecks">The collection of healthchecks.</param>
|
||||
/// <param name="notifications">The collection of healthcheck notification methods.</param>
|
||||
/// <param name="runtimeState">Representation of the state of the Umbraco runtime.</param>
|
||||
/// <param name="serverRegistrar">Provider of server registrations to the distributed cache.</param>
|
||||
/// <param name="mainDom">Representation of the main application domain.</param>
|
||||
/// <param name="scopeProvider">Provides scopes for database operations.</param>
|
||||
/// <param name="logger">The typed logger.</param>
|
||||
/// <param name="profilingLogger">The profiling logger.</param>
|
||||
/// <param name="cronTabParser">Parser of crontab expressions.</param>
|
||||
public HealthCheckNotifier(
|
||||
IOptionsMonitor<HealthChecksSettings> healthChecksSettings,
|
||||
HealthCheckCollection healthChecks,
|
||||
HealthCheckNotificationMethodCollection notifications,
|
||||
IRuntimeState runtimeState,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
IMainDom mainDom,
|
||||
ICoreScopeProvider scopeProvider,
|
||||
ILogger<HealthCheckNotifier> 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<HealthCheckNotifier>("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<HealthCheck> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Hosted service implementation for keep alive feature.
|
||||
/// </summary>
|
||||
[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<KeepAlive> _logger;
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly IProfilingLogger _profilingLogger;
|
||||
private readonly IServerRoleAccessor _serverRegistrar;
|
||||
private KeepAliveSettings _keepAliveSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="KeepAlive" /> class.
|
||||
/// </summary>
|
||||
/// <param name="hostingEnvironment">The current hosting environment</param>
|
||||
/// <param name="mainDom">Representation of the main application domain.</param>
|
||||
/// <param name="keepAliveSettings">The configuration for keep alive settings.</param>
|
||||
/// <param name="logger">The typed logger.</param>
|
||||
/// <param name="profilingLogger">The profiling logger.</param>
|
||||
/// <param name="serverRegistrar">Provider of server registrations to the distributed cache.</param>
|
||||
/// <param name="httpClientFactory">Factory for <see cref="HttpClient" /> instances.</param>
|
||||
public KeepAlive(
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
IMainDom mainDom,
|
||||
IOptionsMonitor<KeepAliveSettings> keepAliveSettings,
|
||||
ILogger<KeepAlive> 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<KeepAlive>("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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Log scrubbing hosted service.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Will only run on non-replica servers.
|
||||
/// </remarks>
|
||||
[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<LogScrubber> _logger;
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly IProfilingLogger _profilingLogger;
|
||||
private readonly ICoreScopeProvider _scopeProvider;
|
||||
private readonly IServerRoleAccessor _serverRegistrar;
|
||||
private LoggingSettings _settings;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LogScrubber" /> class.
|
||||
/// </summary>
|
||||
/// <param name="mainDom">Representation of the main application domain.</param>
|
||||
/// <param name="serverRegistrar">Provider of server registrations to the distributed cache.</param>
|
||||
/// <param name="auditService">Service for handling audit operations.</param>
|
||||
/// <param name="settings">The configuration for logging settings.</param>
|
||||
/// <param name="scopeProvider">Provides scopes for database operations.</param>
|
||||
/// <param name="logger">The typed logger.</param>
|
||||
/// <param name="profilingLogger">The profiling logger.</param>
|
||||
public LogScrubber(
|
||||
IMainDom mainDom,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
IAuditService auditService,
|
||||
IOptionsMonitor<LoggingSettings> settings,
|
||||
ICoreScopeProvider scopeProvider,
|
||||
ILogger<LogScrubber> 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<LogScrubber>("Log scrubbing executing", "Log scrubbing complete"))
|
||||
{
|
||||
_auditService.CleanLogs((int)_settings.MaxLogAge.TotalMinutes);
|
||||
_ = scope.Complete();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -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<ReportSiteTask> _logger;
|
||||
private readonly ITelemetryService _telemetryService;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
|
||||
public ReportSiteTask(
|
||||
ILogger<ReportSiteTask> 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<ReportSiteTask> logger,
|
||||
ITelemetryService telemetryService)
|
||||
: this(logger, telemetryService, StaticServiceProvider.Instance.GetRequiredService<IRuntimeState>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Runs the background task to send the anonymous ID
|
||||
/// to telemetry service
|
||||
/// </summary>
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Hosted service implementation for scheduled publishing feature.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Runs only on non-replica servers.
|
||||
/// </remarks>
|
||||
[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<ScheduledPublishing> _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;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ScheduledPublishing" /> class.
|
||||
/// </summary>
|
||||
public ScheduledPublishing(
|
||||
IRuntimeState runtimeState,
|
||||
IMainDom mainDom,
|
||||
IServerRoleAccessor serverRegistrar,
|
||||
IContentService contentService,
|
||||
IUmbracoContextFactory umbracoContextFactory,
|
||||
ILogger<ScheduledPublishing> 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<PublishResult> result = _contentService.PerformScheduledPublish(DateTime.Now);
|
||||
foreach (IGrouping<PublishResultType, PublishResult> 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Implements periodic database instruction processing as a hosted service.
|
||||
/// </summary>
|
||||
[Obsolete("Use Umbraco.Cms.Infrastructure.BackgroundJobs.ServerRegistration.InstructionProcessJob instead. This class will be removed in Umbraco 14.")]
|
||||
public class InstructionProcessTask : RecurringHostedServiceBase
|
||||
{
|
||||
private readonly ILogger<InstructionProcessTask> _logger;
|
||||
private readonly IServerMessenger _messenger;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private bool _disposedValue;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="InstructionProcessTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="runtimeState">Representation of the state of the Umbraco runtime.</param>
|
||||
/// <param name="messenger">Service broadcasting cache notifications to registered servers.</param>
|
||||
/// <param name="logger">The typed logger.</param>
|
||||
/// <param name="globalSettings">The configuration for global settings.</param>
|
||||
public InstructionProcessTask(IRuntimeState runtimeState, IServerMessenger messenger, ILogger<InstructionProcessTask> logger, IOptions<GlobalSettings> globalSettings)
|
||||
: base(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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Implements periodic server "touching" (to mark as active/deactive) as a hosted service.
|
||||
/// </summary>
|
||||
[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<TouchServerTask> _logger;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IServerRegistrationService _serverRegistrationService;
|
||||
private readonly IServerRoleAccessor _serverRoleAccessor;
|
||||
private GlobalSettings _globalSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TouchServerTask" /> class.
|
||||
/// </summary>
|
||||
/// <param name="runtimeState">Representation of the state of the Umbraco runtime.</param>
|
||||
/// <param name="serverRegistrationService">Services for server registrations.</param>
|
||||
/// <param name="logger">The typed logger.</param>
|
||||
/// <param name="globalSettings">The configuration for global settings.</param>
|
||||
/// <param name="hostingEnvironment">The hostingEnviroment.</param>
|
||||
/// <param name="serverRoleAccessor">The accessor for the server role</param>
|
||||
public TouchServerTask(
|
||||
IRuntimeState runtimeState,
|
||||
IServerRegistrationService serverRegistrationService,
|
||||
IHostingEnvironment hostingEnvironment,
|
||||
ILogger<TouchServerTask> logger,
|
||||
IOptionsMonitor<GlobalSettings> 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Used to cleanup temporary file locations.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
[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<TempFileCleanup> _logger;
|
||||
private readonly IMainDom _mainDom;
|
||||
|
||||
private readonly DirectoryInfo[] _tempFolders;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TempFileCleanup" /> class.
|
||||
/// </summary>
|
||||
/// <param name="ioHelper">Helper service for IO operations.</param>
|
||||
/// <param name="mainDom">Representation of the main application domain.</param>
|
||||
/// <param name="logger">The typed logger.</param>
|
||||
public TempFileCleanup(IIOHelper ioHelper, IMainDom mainDom, ILogger<TempFileCleanup> logger)
|
||||
: base(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
/// Recurring hosted service that executes the temporary file cleanup.
|
||||
/// </summary>
|
||||
public class TemporaryFileCleanup : RecurringHostedServiceBase
|
||||
{
|
||||
private readonly ILogger<TemporaryFileCleanup> _logger;
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IServerRoleAccessor _serverRoleAccessor;
|
||||
private readonly ITemporaryFileService _service;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TemporaryFileCleanup" /> class.
|
||||
/// </summary>
|
||||
public TemporaryFileCleanup(
|
||||
IRuntimeState runtimeState,
|
||||
ILogger<TemporaryFileCleanup> 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;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Umbraco hosted services
|
||||
/// </summary>
|
||||
[Obsolete("Use AddRecurringBackgroundJobs instead")]
|
||||
public static IUmbracoBuilder AddHostedServices(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.AddHostedService<QueuedHostedService>();
|
||||
builder.Services.AddHostedService<HealthCheckNotifier>();
|
||||
builder.Services.AddHostedService<KeepAlive>();
|
||||
builder.Services.AddHostedService<LogScrubber>();
|
||||
builder.Services.AddHostedService<ContentVersionCleanup>();
|
||||
builder.Services.AddHostedService<TemporaryFileCleanup>();
|
||||
builder.Services.AddHostedService<ScheduledPublishing>();
|
||||
builder.Services.AddHostedService<TempFileCleanup>();
|
||||
builder.Services.AddHostedService<InstructionProcessTask>();
|
||||
builder.Services.AddHostedService<TouchServerTask>();
|
||||
builder.Services.AddHostedService(provider =>
|
||||
new ReportSiteTask(
|
||||
provider.GetRequiredService<ILogger<ReportSiteTask>>(),
|
||||
provider.GetRequiredService<ITelemetryService>()));
|
||||
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add Umbraco recurring background jobs
|
||||
/// </summary>
|
||||
@@ -218,19 +192,17 @@ public static partial class UmbracoBuilderExtensions
|
||||
builder.Services.AddRecurringBackgroundJob<ContentVersionCleanupJob>();
|
||||
builder.Services.AddRecurringBackgroundJob<ScheduledPublishingJob>();
|
||||
builder.Services.AddRecurringBackgroundJob<TempFileCleanupJob>();
|
||||
builder.Services.AddRecurringBackgroundJob<TemporaryFileCleanupJob>();
|
||||
builder.Services.AddRecurringBackgroundJob<InstructionProcessJob>();
|
||||
builder.Services.AddRecurringBackgroundJob<TouchServerJob>();
|
||||
builder.Services.AddRecurringBackgroundJob<WebhookFiring>();
|
||||
builder.Services.AddRecurringBackgroundJob<WebhookLoggingCleanup>();
|
||||
builder.Services.AddRecurringBackgroundJob(provider =>
|
||||
new ReportSiteJob(
|
||||
provider.GetRequiredService<ILogger<ReportSiteJob>>(),
|
||||
provider.GetRequiredService<ITelemetryService>()));
|
||||
builder.Services.AddRecurringBackgroundJob<ReportSiteJob>();
|
||||
|
||||
|
||||
builder.Services.AddHostedService<QueuedHostedService>();
|
||||
builder.Services.AddSingleton(RecurringBackgroundJobHostedService.CreateHostedServiceFactory);
|
||||
builder.Services.AddHostedService<RecurringBackgroundJobHostedServiceRunner>();
|
||||
builder.Services.AddHostedService<QueuedHostedService>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -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<IServerRoleAccessor> serverRoleAccessor,
|
||||
[Frozen] Mock<IRuntimeState> runtimeState,
|
||||
[Frozen] Mock<IContentVersionService> 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<DateTime>()), Times.Never);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public async Task ContentVersionCleanup_RuntimeLevelNotRun_DoesNotCleanupWillRepeat(
|
||||
[Frozen] Mock<IOptionsMonitor<ContentSettings>> settings,
|
||||
[Frozen] Mock<IMainDom> mainDom,
|
||||
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
|
||||
[Frozen] Mock<IRuntimeState> runtimeState,
|
||||
[Frozen] Mock<IContentVersionService> 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<DateTime>()), Times.Never);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public async Task ContentVersionCleanup_ServerRoleUnknown_DoesNotCleanupWillRepeat(
|
||||
[Frozen] Mock<IOptionsMonitor<ContentSettings>> settings,
|
||||
[Frozen] Mock<IMainDom> mainDom,
|
||||
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
|
||||
[Frozen] Mock<IRuntimeState> runtimeState,
|
||||
[Frozen] Mock<IContentVersionService> 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<DateTime>()), Times.Never);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[AutoMoqData]
|
||||
public async Task ContentVersionCleanup_NotMainDom_DoesNotCleanupWillNotRepeat(
|
||||
[Frozen] Mock<IOptionsMonitor<ContentSettings>> settings,
|
||||
[Frozen] Mock<IMainDom> mainDom,
|
||||
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
|
||||
[Frozen] Mock<IRuntimeState> runtimeState,
|
||||
[Frozen] Mock<IContentVersionService> 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<DateTime>()), Times.Never);
|
||||
}
|
||||
@@ -117,7 +48,7 @@ internal class ContentVersionCleanupTest
|
||||
[Frozen] Mock<IServerRoleAccessor> serverRoleAccessor,
|
||||
[Frozen] Mock<IRuntimeState> runtimeState,
|
||||
[Frozen] Mock<IContentVersionService> 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<DateTime>()), Times.Once);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<IHealthCheckNotificationMethod> _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<HealthCheckResults>(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<DisabledHealthCheckSettings> { new() { Id = Guid.Parse(Check3Id) } },
|
||||
},
|
||||
DisabledChecks = new List<DisabledHealthCheckSettings> { new() { Id = Guid.Parse(Check2Id) } },
|
||||
};
|
||||
var checks = new HealthCheckCollection(() => new List<HealthCheck>
|
||||
{
|
||||
new TestHealthCheck1(),
|
||||
new TestHealthCheck2(),
|
||||
new TestHealthCheck3(),
|
||||
});
|
||||
|
||||
_mockNotificationMethod = new Mock<IHealthCheckNotificationMethod>();
|
||||
_mockNotificationMethod.SetupGet(x => x.Enabled).Returns(notificationEnabled);
|
||||
var notifications = new HealthCheckNotificationMethodCollection(() =>
|
||||
new List<IHealthCheckNotificationMethod> { _mockNotificationMethod.Object });
|
||||
|
||||
var mockRunTimeState = new Mock<IRuntimeState>();
|
||||
mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel);
|
||||
|
||||
var mockServerRegistrar = new Mock<IServerRoleAccessor>();
|
||||
mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole);
|
||||
|
||||
var mockMainDom = new Mock<IMainDom>();
|
||||
mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom);
|
||||
|
||||
var mockScopeProvider = new Mock<IScopeProvider>();
|
||||
var mockLogger = new Mock<ILogger<HealthCheckNotifier>>();
|
||||
var mockProfilingLogger = new Mock<IProfilingLogger>();
|
||||
|
||||
return new HealthCheckNotifier(
|
||||
new TestOptionsMonitor<HealthChecksSettings>(settings),
|
||||
checks,
|
||||
notifications,
|
||||
mockRunTimeState.Object,
|
||||
mockServerRegistrar.Object,
|
||||
mockMainDom.Object,
|
||||
mockScopeProvider.Object,
|
||||
mockLogger.Object,
|
||||
mockProfilingLogger.Object,
|
||||
Mock.Of<ICronTabParser>());
|
||||
}
|
||||
|
||||
private void VerifyNotificationsNotSent() => VerifyNotificationsSentTimes(Times.Never());
|
||||
|
||||
private void VerifyNotificationsSent() => VerifyNotificationsSentTimes(Times.Once());
|
||||
|
||||
private void VerifyNotificationsSentTimes(Times times) =>
|
||||
_mockNotificationMethod.Verify(x => x.SendAsync(It.IsAny<HealthCheckResults>()), 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<IEnumerable<HealthCheckStatus>> GetStatus() => Enumerable.Empty<HealthCheckStatus>();
|
||||
}
|
||||
}
|
||||
@@ -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<HttpMessageHandler> _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<IHostingEnvironment>();
|
||||
mockHostingEnvironment.SetupGet(x => x.ApplicationMainUrl).Returns(new Uri(ApplicationUrl));
|
||||
mockHostingEnvironment.Setup(x => x.ToAbsolute(It.IsAny<string>()))
|
||||
.Returns((string s) => s.TrimStart('~'));
|
||||
|
||||
var mockServerRegistrar = new Mock<IServerRoleAccessor>();
|
||||
mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole);
|
||||
|
||||
var mockMainDom = new Mock<IMainDom>();
|
||||
mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom);
|
||||
|
||||
var mockScopeProvider = new Mock<IScopeProvider>();
|
||||
var mockLogger = new Mock<ILogger<KeepAlive>>();
|
||||
var mockProfilingLogger = new Mock<IProfilingLogger>();
|
||||
|
||||
_mockHttpMessageHandler = new Mock<HttpMessageHandler>();
|
||||
_mockHttpMessageHandler.Protected()
|
||||
.Setup<Task<HttpResponseMessage>>(
|
||||
"SendAsync",
|
||||
ItExpr.IsAny<HttpRequestMessage>(),
|
||||
ItExpr.IsAny<CancellationToken>())
|
||||
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK))
|
||||
.Verifiable();
|
||||
_mockHttpMessageHandler.As<IDisposable>().Setup(s => s.Dispose());
|
||||
var httpClient = new HttpClient(_mockHttpMessageHandler.Object);
|
||||
|
||||
var mockHttpClientFactory = new Mock<IHttpClientFactory>(MockBehavior.Strict);
|
||||
mockHttpClientFactory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(httpClient);
|
||||
|
||||
return new KeepAlive(
|
||||
mockHostingEnvironment.Object,
|
||||
mockMainDom.Object,
|
||||
new TestOptionsMonitor<KeepAliveSettings>(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<HttpRequestMessage>(x => x.RequestUri.ToString() == $"{ApplicationUrl}/api/keepalive/ping"),
|
||||
ItExpr.IsAny<CancellationToken>());
|
||||
}
|
||||
@@ -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<IAuditService> _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<IServerRoleAccessor>();
|
||||
mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole);
|
||||
|
||||
var mockMainDom = new Mock<IMainDom>();
|
||||
mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom);
|
||||
|
||||
var mockScope = new Mock<IScope>();
|
||||
var mockScopeProvider = new Mock<ICoreScopeProvider>();
|
||||
mockScopeProvider
|
||||
.Setup(x => x.CreateCoreScope(
|
||||
It.IsAny<IsolationLevel>(),
|
||||
It.IsAny<RepositoryCacheMode>(),
|
||||
It.IsAny<IEventDispatcher>(),
|
||||
It.IsAny<IScopedNotificationPublisher>(),
|
||||
It.IsAny<bool?>(),
|
||||
It.IsAny<bool>(),
|
||||
It.IsAny<bool>()))
|
||||
.Returns(mockScope.Object);
|
||||
var mockLogger = new Mock<ILogger<LogScrubber>>();
|
||||
var mockProfilingLogger = new Mock<IProfilingLogger>();
|
||||
|
||||
_mockAuditService = new Mock<IAuditService>();
|
||||
|
||||
return new LogScrubber(
|
||||
mockMainDom.Object,
|
||||
mockServerRegistrar.Object,
|
||||
_mockAuditService.Object,
|
||||
new TestOptionsMonitor<LoggingSettings>(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<int>(y => y == MaxLogAgeInMinutes)), times);
|
||||
}
|
||||
@@ -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<IContentService> _mockContentService;
|
||||
private Mock<ILogger<ScheduledPublishing>> _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<IRuntimeState>();
|
||||
mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel);
|
||||
|
||||
var mockServerRegistrar = new Mock<IServerRoleAccessor>();
|
||||
mockServerRegistrar.Setup(x => x.CurrentServerRole).Returns(serverRole);
|
||||
|
||||
var mockMainDom = new Mock<IMainDom>();
|
||||
mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom);
|
||||
|
||||
_mockContentService = new Mock<IContentService>();
|
||||
|
||||
var mockUmbracoContextFactory = new Mock<IUmbracoContextFactory>();
|
||||
mockUmbracoContextFactory.Setup(x => x.EnsureUmbracoContext())
|
||||
.Returns(new UmbracoContextReference(null, false, null));
|
||||
|
||||
_mockLogger = new Mock<ILogger<ScheduledPublishing>>();
|
||||
|
||||
var mockServerMessenger = new Mock<IServerMessenger>();
|
||||
|
||||
var mockScopeProvider = new Mock<ICoreScopeProvider>();
|
||||
mockScopeProvider
|
||||
.Setup(x => x.CreateCoreScope(
|
||||
It.IsAny<IsolationLevel>(),
|
||||
It.IsAny<RepositoryCacheMode>(),
|
||||
It.IsAny<IEventDispatcher>(),
|
||||
It.IsAny<IScopedNotificationPublisher>(),
|
||||
It.IsAny<bool?>(),
|
||||
It.IsAny<bool>(),
|
||||
It.IsAny<bool>()))
|
||||
.Returns(Mock.Of<IScope>());
|
||||
|
||||
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<DateTime>()), times);
|
||||
}
|
||||
@@ -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<IServerMessenger> _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<IRuntimeState>();
|
||||
mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel);
|
||||
|
||||
var mockLogger = new Mock<ILogger<InstructionProcessTask>>();
|
||||
|
||||
_mockDatabaseServerMessenger = new Mock<IServerMessenger>();
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -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<IServerRegistrationService> _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<IHostingEnvironment>();
|
||||
mockRequestAccessor.SetupGet(x => x.ApplicationMainUrl)
|
||||
.Returns(!string.IsNullOrEmpty(applicationUrl) ? new Uri(ApplicationUrl) : null);
|
||||
|
||||
var mockRunTimeState = new Mock<IRuntimeState>();
|
||||
mockRunTimeState.SetupGet(x => x.Level).Returns(runtimeLevel);
|
||||
|
||||
var mockLogger = new Mock<ILogger<TouchServerTask>>();
|
||||
|
||||
_mockServerRegistrationService = new Mock<IServerRegistrationService>();
|
||||
|
||||
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<GlobalSettings>(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<string>(y => y == ApplicationUrl),
|
||||
It.Is<TimeSpan>(y => y == _staleServerTimeout)),
|
||||
times);
|
||||
}
|
||||
@@ -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<IIOHelper> _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<IMainDom>();
|
||||
mockMainDom.SetupGet(x => x.IsMainDom).Returns(isMainDom);
|
||||
|
||||
_mockIOHelper = new Mock<IIOHelper>();
|
||||
_mockIOHelper.Setup(x => x.GetTempFolders())
|
||||
.Returns(new DirectoryInfo[] { new(_testPath) });
|
||||
_mockIOHelper.Setup(x => x.CleanFolder(It.IsAny<DirectoryInfo>(), It.IsAny<TimeSpan>()))
|
||||
.Returns(CleanFolderResult.Success());
|
||||
|
||||
var mockLogger = new Mock<ILogger<TempFileCleanup>>();
|
||||
|
||||
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<DirectoryInfo>(y => y.FullName == _testPath), It.IsAny<TimeSpan>()), times);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user