Merge pull request #9503 from AndyButland/feature/clean-up

NetCore: updated some code to match linting rules
This commit is contained in:
Bjarke Berg
2020-12-07 07:54:22 +01:00
committed by GitHub
91 changed files with 991 additions and 637 deletions

View File

@@ -1,4 +1,8 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -13,6 +17,7 @@ using Umbraco.Core.Sync;
using Umbraco.Infrastructure.Configuration.Extensions;
using Umbraco.Infrastructure.HealthCheck;
using Umbraco.Web.HealthCheck;
using Umbraco.Web.HealthCheck.NotificationMethods;
namespace Umbraco.Infrastructure.HostedServices
{
@@ -31,6 +36,19 @@ namespace Umbraco.Infrastructure.HostedServices
private readonly ILogger<HealthCheckNotifier> _logger;
private readonly IProfilingLogger _profilingLogger;
/// <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(
IOptions<HealthChecksSettings> healthChecksSettings,
HealthCheckCollection healthChecks,
@@ -42,8 +60,9 @@ namespace Umbraco.Infrastructure.HostedServices
ILogger<HealthCheckNotifier> logger,
IProfilingLogger profilingLogger,
ICronTabParser cronTabParser)
: base(healthChecksSettings.Value.Notification.Period,
healthChecksSettings.Value.GetNotificationDelay(cronTabParser, DateTime.Now, DefaultDelay))
: base(
healthChecksSettings.Value.Notification.Period,
healthChecksSettings.Value.GetNotificationDelay(cronTabParser, DateTime.Now, DefaultDelay))
{
_healthChecksSettings = healthChecksSettings.Value;
_healthChecks = healthChecks;
@@ -88,25 +107,25 @@ namespace Umbraco.Infrastructure.HostedServices
// 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 (var scope = _scopeProvider.CreateScope())
using (IScope scope = _scopeProvider.CreateScope())
using (_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.
var disabledCheckIds = _healthChecksSettings.Notification.DisabledChecks
Guid[] disabledCheckIds = _healthChecksSettings.Notification.DisabledChecks
.Select(x => x.Id)
.Union(_healthChecksSettings.DisabledChecks
.Select(x => x.Id))
.Distinct()
.ToArray();
var checks = _healthChecks
IEnumerable<Core.HealthCheck.HealthCheck> checks = _healthChecks
.Where(x => disabledCheckIds.Contains(x.Id) == false);
var results = new HealthCheckResults(checks);
results.LogResults();
// Send using registered notification methods that are enabled.
foreach (var notificationMethod in _notifications.Where(x => x.Enabled))
foreach (IHealthCheckNotificationMethod notificationMethod in _notifications.Where(x => x.Enabled))
{
await notificationMethod.SendAsync(results);
}

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -24,7 +27,24 @@ namespace Umbraco.Infrastructure.HostedServices
private readonly IServerRegistrar _serverRegistrar;
private readonly IHttpClientFactory _httpClientFactory;
public KeepAlive(IRequestAccessor requestAccessor, IMainDom mainDom, IOptions<KeepAliveSettings> keepAliveSettings, ILogger<KeepAlive> logger, IProfilingLogger profilingLogger, IServerRegistrar serverRegistrar, IHttpClientFactory httpClientFactory)
/// <summary>
/// Initializes a new instance of the <see cref="KeepAlive"/> class.
/// </summary>
/// <param name="requestAccessor">Accessor for the current request.</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(
IRequestAccessor requestAccessor,
IMainDom mainDom,
IOptions<KeepAliveSettings> keepAliveSettings,
ILogger<KeepAlive> logger,
IProfilingLogger profilingLogger,
IServerRegistrar serverRegistrar,
IHttpClientFactory httpClientFactory)
: base(TimeSpan.FromMinutes(5), DefaultDelay)
{
_requestAccessor = requestAccessor;
@@ -79,8 +99,8 @@ namespace Umbraco.Infrastructure.HostedServices
}
var request = new HttpRequestMessage(HttpMethod.Get, keepAlivePingUrl);
var httpClient = _httpClientFactory.CreateClient();
await httpClient.SendAsync(request);
HttpClient httpClient = _httpClientFactory.CreateClient();
_ = await httpClient.SendAsync(request);
}
catch (Exception ex)
{

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -27,7 +30,24 @@ namespace Umbraco.Infrastructure.HostedServices
private readonly ILogger<LogScrubber> _logger;
private readonly IScopeProvider _scopeProvider;
public LogScrubber(IMainDom mainDom, IServerRegistrar serverRegistrar, IAuditService auditService, IOptions<LoggingSettings> settings, IScopeProvider scopeProvider, ILogger<LogScrubber> logger, IProfilingLogger profilingLogger)
/// <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,
IServerRegistrar serverRegistrar,
IAuditService auditService,
IOptions<LoggingSettings> settings,
IScopeProvider scopeProvider,
ILogger<LogScrubber> logger,
IProfilingLogger profilingLogger)
: base(TimeSpan.FromHours(4), DefaultDelay)
{
_mainDom = mainDom;
@@ -39,32 +59,34 @@ namespace Umbraco.Infrastructure.HostedServices
_profilingLogger = profilingLogger;
}
internal override async Task PerformExecuteAsync(object state)
internal override Task PerformExecuteAsync(object state)
{
switch (_serverRegistrar.GetCurrentServerRole())
{
case ServerRole.Replica:
_logger.LogDebug("Does not run on replica servers.");
return;
return Task.CompletedTask;
case ServerRole.Unknown:
_logger.LogDebug("Does not run on servers with unknown role.");
return;
return Task.CompletedTask;
}
// 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;
return Task.CompletedTask;
}
// Ensure we use an explicit scope since we are running on a background thread.
using (var scope = _scopeProvider.CreateScope())
using (IScope scope = _scopeProvider.CreateScope())
using (_profilingLogger.DebugDuration<LogScrubber>("Log scrubbing executing", "Log scrubbing complete"))
{
_auditService.CleanLogs((int)_settings.MaxLogAge.TotalMinutes);
scope.Complete();
_ = scope.Complete();
}
return Task.CompletedTask;
}
}
}

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
@@ -13,44 +16,54 @@ namespace Umbraco.Infrastructure.HostedServices
/// </remarks>
public abstract class RecurringHostedServiceBase : IHostedService, IDisposable
{
/// <summary>
/// The default delay to use for recurring tasks for the first run after application start-up if no alternative is configured.
/// </summary>
protected static readonly TimeSpan DefaultDelay = TimeSpan.FromMinutes(3);
private readonly TimeSpan _period;
private readonly TimeSpan _delay;
private Timer _timer;
/// <summary>
/// Initializes a new instance of the <see cref="RecurringHostedServiceBase"/> class.
/// </summary>
/// <param name="period">Timepsan representing how often the task should recur.</param>
/// <param name="delay">Timespan represeting the initial delay after application start-up before the first run of the task occurs.</param>
protected RecurringHostedServiceBase(TimeSpan period, TimeSpan delay)
{
_period = period;
_delay = delay;
}
/// <inheritdoc/>
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(ExecuteAsync, null, (int)_delay.TotalMilliseconds, (int)_period.TotalMilliseconds);
return Task.CompletedTask;
}
public async void ExecuteAsync(object state)
{
/// <summary>
/// Executes the task.
/// </summary>
/// <param name="state">The task state.</param>
public async void ExecuteAsync(object state) =>
// Delegate work to method returning a task, that can be called and asserted in a unit test.
// Without this there can be behaviour where tests pass, but an error within them causes the test
// running process to crash.
// Hat-tip: https://stackoverflow.com/a/14207615/489433
await PerformExecuteAsync(state);
}
internal abstract Task PerformExecuteAsync(object state);
/// <inheritdoc/>
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
/// <inheritdoc/>
public void Dispose() => _timer?.Dispose();
}
}

View File

@@ -1,8 +1,13 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Umbraco.Core;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
using Umbraco.Core.Sync;
using Umbraco.Web;
@@ -19,18 +24,35 @@ namespace Umbraco.Infrastructure.HostedServices
private readonly IContentService _contentService;
private readonly ILogger<ScheduledPublishing> _logger;
private readonly IMainDom _mainDom;
private readonly IRuntimeState _runtime;
private readonly IRuntimeState _runtimeState;
private readonly IServerMessenger _serverMessenger;
private readonly IBackOfficeSecurityFactory _backofficeSecurityFactory;
private readonly IServerRegistrar _serverRegistrar;
private readonly IUmbracoContextFactory _umbracoContextFactory;
/// <summary>
/// Initializes a new instance of the <see cref="ScheduledPublishing"/> class.
/// </summary>
/// <param name="runtimeState">Representation of the state of the Umbraco runtime.</param>
/// <param name="mainDom">Representation of the main application domain.</param>
/// <param name="serverRegistrar">Provider of server registrations to the distributed cache.</param>
/// <param name="contentService">Service for handling content operations.</param>
/// <param name="umbracoContextFactory">Service for creating and managing Umbraco context.</param>
/// <param name="logger">The typed logger.</param>
/// <param name="serverMessenger">Service broadcasting cache notifications to registered servers.</param>
/// <param name="backofficeSecurityFactory">Creates and manages <see cref="IBackOfficeSecurity"/> instances.</param>
public ScheduledPublishing(
IRuntimeState runtime, IMainDom mainDom, IServerRegistrar serverRegistrar, IContentService contentService,
IUmbracoContextFactory umbracoContextFactory, ILogger<ScheduledPublishing> logger, IServerMessenger serverMessenger, IBackOfficeSecurityFactory backofficeSecurityFactory)
IRuntimeState runtimeState,
IMainDom mainDom,
IServerRegistrar serverRegistrar,
IContentService contentService,
IUmbracoContextFactory umbracoContextFactory,
ILogger<ScheduledPublishing> logger,
IServerMessenger serverMessenger,
IBackOfficeSecurityFactory backofficeSecurityFactory)
: base(TimeSpan.FromMinutes(1), DefaultDelay)
{
_runtime = runtime;
_runtimeState = runtimeState;
_mainDom = mainDom;
_serverRegistrar = serverRegistrar;
_contentService = contentService;
@@ -40,35 +62,35 @@ namespace Umbraco.Infrastructure.HostedServices
_backofficeSecurityFactory = backofficeSecurityFactory;
}
internal override async Task PerformExecuteAsync(object state)
internal override Task PerformExecuteAsync(object state)
{
if (Suspendable.ScheduledPublishing.CanRun == false)
{
return;
return Task.CompletedTask;
}
switch (_serverRegistrar.GetCurrentServerRole())
{
case ServerRole.Replica:
_logger.LogDebug("Does not run on replica servers.");
return;
return Task.CompletedTask;
case ServerRole.Unknown:
_logger.LogDebug("Does not run on servers with unknown role.");
return;
return Task.CompletedTask;
}
// 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;
return Task.CompletedTask;
}
// Do NOT run publishing if not properly running
if (_runtime.Level != RuntimeLevel.Run)
if (_runtimeState.Level != RuntimeLevel.Run)
{
_logger.LogDebug("Does not run if run level is not Run.");
return;
return Task.CompletedTask;
}
try
@@ -85,16 +107,17 @@ namespace Umbraco.Infrastructure.HostedServices
// - and we should definitively *not* have to flush it here (should be auto)
//
_backofficeSecurityFactory.EnsureBackOfficeSecurity();
using var contextReference = _umbracoContextFactory.EnsureUmbracoContext();
using UmbracoContextReference contextReference = _umbracoContextFactory.EnsureUmbracoContext();
try
{
// Run
var result = _contentService.PerformScheduledPublish(DateTime.Now);
foreach (var grouped in result.GroupBy(x => x.Result))
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);
grouped.Count(),
grouped.Key);
}
}
finally
@@ -112,7 +135,7 @@ namespace Umbraco.Infrastructure.HostedServices
_logger.LogError(ex, "Failed.");
}
return;
return Task.CompletedTask;
}
}
}

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -20,6 +23,10 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
/// <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(globalSettings.Value.DatabaseServerMessenger.TimeBetweenSyncOperations, TimeSpan.FromMinutes(1))
{
@@ -28,11 +35,11 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
_logger = logger;
}
internal override async Task PerformExecuteAsync(object state)
internal override Task PerformExecuteAsync(object state)
{
if (_runtimeState.Level != RuntimeLevel.Run)
{
return;
return Task.CompletedTask;
}
try
@@ -43,6 +50,8 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
{
_logger.LogError(e, "Failed (will repeat).");
}
return Task.CompletedTask;
}
}
}

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@@ -18,11 +21,16 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
private readonly IServerRegistrationService _serverRegistrationService;
private readonly IRequestAccessor _requestAccessor;
private readonly ILogger<TouchServerTask> _logger;
private GlobalSettings _globalSettings;
private readonly 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="requestAccessor">Accessor for the current request.</param>
/// <param name="logger">The typed logger.</param>
/// <param name="globalSettings">The configuration for global settings.</param>
public TouchServerTask(IRuntimeState runtimeState, IServerRegistrationService serverRegistrationService, IRequestAccessor requestAccessor, ILogger<TouchServerTask> logger, IOptions<GlobalSettings> globalSettings)
: base(globalSettings.Value.DatabaseServerRegistrar.WaitTimeBetweenCalls, TimeSpan.FromSeconds(15))
{
@@ -33,18 +41,18 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
_globalSettings = globalSettings.Value;
}
internal override async Task PerformExecuteAsync(object state)
internal override Task PerformExecuteAsync(object state)
{
if (_runtimeState.Level != RuntimeLevel.Run)
{
return;
return Task.CompletedTask;
}
var serverAddress = _requestAccessor.GetApplicationUrl()?.ToString();
if (serverAddress.IsNullOrWhiteSpace())
{
_logger.LogWarning("No umbracoApplicationUrl for service (yet), skip.");
return;
return Task.CompletedTask;
}
try
@@ -57,6 +65,8 @@ namespace Umbraco.Infrastructure.HostedServices.ServerRegistration
{
_logger.LogError(ex, "Failed to update server record in database.");
}
return Task.CompletedTask;
}
}
}

View File

@@ -1,4 +1,7 @@
using System;
// Copyright (c) Umbraco.
// See LICENSE for more details.
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
@@ -23,6 +26,12 @@ namespace Umbraco.Infrastructure.HostedServices
private readonly DirectoryInfo[] _tempFolders;
private readonly TimeSpan _age = TimeSpan.FromDays(1);
/// <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(TimeSpan.FromMinutes(60), DefaultDelay)
{
@@ -33,33 +42,33 @@ namespace Umbraco.Infrastructure.HostedServices
_tempFolders = _ioHelper.GetTempFolders();
}
internal override async Task PerformExecuteAsync(object state)
internal override Task PerformExecuteAsync(object state)
{
// Ensure we do not run if not main domain
if (_mainDom.IsMainDom == false)
{
_logger.LogDebug("Does not run if not MainDom.");
return;
return Task.CompletedTask;
}
foreach (var folder in _tempFolders)
foreach (DirectoryInfo folder in _tempFolders)
{
CleanupFolder(folder);
}
return;
return Task.CompletedTask;
}
private void CleanupFolder(DirectoryInfo folder)
{
var result = _ioHelper.CleanFolder(folder, _age);
CleanFolderResult result = _ioHelper.CleanFolder(folder, _age);
switch (result.Status)
{
case CleanFolderResultStatus.FailedAsDoesNotExist:
_logger.LogDebug("The cleanup folder doesn't exist {Folder}", folder.FullName);
break;
case CleanFolderResultStatus.FailedWithException:
foreach (var error in result.Errors)
foreach (CleanFolderResult.Error error in result.Errors)
{
_logger.LogError(error.Exception, "Could not delete temp file {FileName}", error.ErroringFile.FullName);
}
@@ -74,8 +83,8 @@ namespace Umbraco.Infrastructure.HostedServices
return;
}
var files = folder.GetFiles("*.*", SearchOption.AllDirectories);
foreach (var file in files)
FileInfo[] files = folder.GetFiles("*.*", SearchOption.AllDirectories);
foreach (FileInfo file in files)
{
if (DateTime.UtcNow - file.LastWriteTimeUtc > _age)
{