From 9c041926c65a73950c705959b5f8997756228cf1 Mon Sep 17 00:00:00 2001 From: Erik-Jan Westendorp Date: Tue, 21 Nov 2023 14:59:00 +0100 Subject: [PATCH 1/3] Add HealthCheckCompletedNotification --- .../HealthChecks/HealthCheckResults.cs | 2 ++ .../HealthCheckCompletedNotification.cs | 13 +++++++++++++ .../Jobs/HealthCheckNotifierJob.cs | 9 ++++++++- .../HealthChecks/HealthCheckController.cs | 18 +++++++++++++++++- .../Jobs/HealthCheckNotifierJobTests.cs | 4 +++- 5 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/Umbraco.Core/Notifications/HealthCheckCompletedNotification.cs diff --git a/src/Umbraco.Core/HealthChecks/HealthCheckResults.cs b/src/Umbraco.Core/HealthChecks/HealthCheckResults.cs index afeb8ba9fa3b..f88b96c9d662 100644 --- a/src/Umbraco.Core/HealthChecks/HealthCheckResults.cs +++ b/src/Umbraco.Core/HealthChecks/HealthCheckResults.cs @@ -53,6 +53,8 @@ public static async Task Create(IEnumerable che return new HealthCheckResults(results, allChecksSuccessful); } + public static async Task Create(HealthCheck check) => await Create(new List() { check }); + public void LogResults() { Logger.LogInformation("Scheduled health check results:"); diff --git a/src/Umbraco.Core/Notifications/HealthCheckCompletedNotification.cs b/src/Umbraco.Core/Notifications/HealthCheckCompletedNotification.cs new file mode 100644 index 000000000000..67df86deb169 --- /dev/null +++ b/src/Umbraco.Core/Notifications/HealthCheckCompletedNotification.cs @@ -0,0 +1,13 @@ +using Umbraco.Cms.Core.HealthChecks; + +namespace Umbraco.Cms.Core.Notifications; + +public class HealthCheckCompletedNotification : INotification +{ + public HealthCheckCompletedNotification(HealthCheckResults healthCheckResults) + { + HealthCheckResults = healthCheckResults; + } + + public HealthCheckResults HealthCheckResults { get; } +} diff --git a/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJob.cs b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJob.cs index ba78af33b4ca..369f4230a147 100644 --- a/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJob.cs +++ b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJob.cs @@ -6,9 +6,11 @@ using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.HealthChecks; using Umbraco.Cms.Core.HealthChecks.NotificationMethods; using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Runtime; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; @@ -38,6 +40,7 @@ public event EventHandler PeriodChanged private readonly ILogger _logger; private readonly HealthCheckNotificationMethodCollection _notifications; private readonly IProfilingLogger _profilingLogger; + private readonly IEventAggregator _eventAggregator; private readonly ICoreScopeProvider _scopeProvider; private HealthChecksSettings _healthChecksSettings; @@ -58,7 +61,8 @@ public HealthCheckNotifierJob( ICoreScopeProvider scopeProvider, ILogger logger, IProfilingLogger profilingLogger, - ICronTabParser cronTabParser) + ICronTabParser cronTabParser, + IEventAggregator eventAggregator) { _healthChecksSettings = healthChecksSettings.CurrentValue; _healthChecks = healthChecks; @@ -66,6 +70,7 @@ public HealthCheckNotifierJob( _scopeProvider = scopeProvider; _logger = logger; _profilingLogger = profilingLogger; + _eventAggregator = eventAggregator; Period = healthChecksSettings.CurrentValue.Notification.Period; Delay = DelayCalculator.GetDelay(healthChecksSettings.CurrentValue.Notification.FirstRunTime, cronTabParser, logger, TimeSpan.FromMinutes(3)); @@ -106,6 +111,8 @@ public async Task RunJobAsync() HealthCheckResults results = await HealthCheckResults.Create(checks); results.LogResults(); + _eventAggregator.Publish(new HealthCheckCompletedNotification(results)); + // Send using registered notification methods that are enabled. foreach (IHealthCheckNotificationMethod notificationMethod in _notifications.Where(x => x.Enabled)) { diff --git a/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs b/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs index 9744ed8c5f82..50a75e4ed48a 100644 --- a/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs +++ b/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs @@ -7,7 +7,9 @@ using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.HealthChecks; +using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Web.BackOffice.Controllers; using Umbraco.Cms.Web.Common.Attributes; using Umbraco.Cms.Web.Common.Authorization; @@ -24,14 +26,18 @@ public class HealthCheckController : UmbracoAuthorizedJsonController private readonly HealthCheckCollection _checks; private readonly IList _disabledCheckIds; private readonly ILogger _logger; + private readonly IEventAggregator _eventAggregator; + private readonly HealthChecksSettings _healthChecksSettings; /// /// Initializes a new instance of the class. /// - public HealthCheckController(HealthCheckCollection checks, ILogger logger, IOptions healthChecksSettings) + public HealthCheckController(HealthCheckCollection checks, ILogger logger, IOptions healthChecksSettings, IEventAggregator eventAggregator) { _checks = checks ?? throw new ArgumentNullException(nameof(checks)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _eventAggregator = eventAggregator ?? throw new ArgumentException(nameof(eventAggregator)); + _healthChecksSettings = healthChecksSettings?.Value ?? throw new ArgumentException(nameof(healthChecksSettings)); HealthChecksSettings healthCheckConfig = healthChecksSettings.Value ?? throw new ArgumentNullException(nameof(healthChecksSettings)); @@ -80,6 +86,16 @@ public async Task GetStatus(Guid id) { _logger.LogDebug("Running health check: " + check.Name); } + + if (!_healthChecksSettings.Notification.Enabled) + { + return await check.GetStatus(); + } + + HealthCheckResults results = await HealthCheckResults.Create(check); + _eventAggregator.Publish(new HealthCheckCompletedNotification(results)); + + return await check.GetStatus(); } catch (Exception ex) diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJobTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJobTests.cs index cf9883603b11..316605a04e3a 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJobTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJobTests.cs @@ -10,6 +10,7 @@ using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.HealthChecks; using Umbraco.Cms.Core.HealthChecks.NotificationMethods; using Umbraco.Cms.Core.Logging; @@ -105,7 +106,8 @@ private HealthCheckNotifierJob CreateHealthCheckNotifier( mockScopeProvider.Object, mockLogger.Object, mockProfilingLogger.Object, - Mock.Of()); + Mock.Of(), + Mock.Of()); } private void VerifyNotificationsNotSent() => VerifyNotificationsSentTimes(Times.Never()); From e46dd73e2d959fe7ae00f111aa440d1b388f8fd3 Mon Sep 17 00:00:00 2001 From: Erik-Jan Westendorp Date: Wed, 22 Nov 2023 11:25:42 +0100 Subject: [PATCH 2/3] Make HealthCheckController Obsolete --- .../HealthChecks/HealthCheckController.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs b/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs index 50a75e4ed48a..1880b26cedf0 100644 --- a/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs +++ b/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs @@ -3,10 +3,12 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.HealthChecks; using Umbraco.Cms.Core.Notifications; @@ -32,6 +34,15 @@ public class HealthCheckController : UmbracoAuthorizedJsonController /// /// Initializes a new instance of the class. /// + [Obsolete("Use constructor that accepts IEventAggregator as a parameter, scheduled for removal in V14")] + public HealthCheckController(HealthCheckCollection checks, ILogger logger, IOptions healthChecksSettings) + : this(checks, logger, healthChecksSettings, StaticServiceProvider.Instance.GetRequiredService()) + { } + + /// + /// Initializes a new instance of the class. + /// + [ActivatorUtilitiesConstructor] public HealthCheckController(HealthCheckCollection checks, ILogger logger, IOptions healthChecksSettings, IEventAggregator eventAggregator) { _checks = checks ?? throw new ArgumentNullException(nameof(checks)); From 7645e9553524d85d28acf8766799271cde194747 Mon Sep 17 00:00:00 2001 From: Erik-Jan Westendorp Date: Wed, 22 Nov 2023 11:30:42 +0100 Subject: [PATCH 3/3] Make HealthCheckNotifierJob Contructor Obsolete --- .../Jobs/HealthCheckNotifierJob.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJob.cs b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJob.cs index 369f4230a147..a3dc6ec779de 100644 --- a/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJob.cs +++ b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/HealthCheckNotifierJob.cs @@ -1,11 +1,13 @@ // Copyright (c) Umbraco. // See LICENSE for more details. +using Microsoft.Extensions.DependencyInjection; 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.DependencyInjection; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.HealthChecks; using Umbraco.Cms.Core.HealthChecks.NotificationMethods; @@ -44,6 +46,26 @@ public event EventHandler PeriodChanged private readonly ICoreScopeProvider _scopeProvider; private HealthChecksSettings _healthChecksSettings; + [Obsolete("Use constructor that accepts IEventAggregator as a parameter, scheduled for removal in V14")] + public HealthCheckNotifierJob( + IOptionsMonitor healthChecksSettings, + HealthCheckCollection healthChecks, + HealthCheckNotificationMethodCollection notifications, + ICoreScopeProvider scopeProvider, + ILogger logger, + IProfilingLogger profilingLogger, + ICronTabParser cronTabParser) + : this( + healthChecksSettings, + healthChecks, + notifications, + scopeProvider, + logger, + profilingLogger, + cronTabParser, + StaticServiceProvider.Instance.GetRequiredService()) + { } + /// /// Initializes a new instance of the class. ///