Skip to content

Commit

Permalink
Add HealthCheckCompletedNotification (#15276)
Browse files Browse the repository at this point in the history
  • Loading branch information
erikjanwestendorp authored Nov 30, 2023
1 parent d088ed8 commit c0e0e7b
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/Umbraco.Core/HealthChecks/HealthCheckResults.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public static async Task<HealthCheckResults> Create(IEnumerable<HealthCheck> che
return new HealthCheckResults(results, allChecksSuccessful);
}

public static async Task<HealthCheckResults> Create(HealthCheck check) => await Create(new List<HealthCheck>() { check });

public void LogResults()
{
Logger.LogInformation("Scheduled health check results:");
Expand Down
13 changes: 13 additions & 0 deletions src/Umbraco.Core/Notifications/HealthCheckCompletedNotification.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
// 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;
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;
Expand Down Expand Up @@ -38,9 +42,30 @@ public event EventHandler PeriodChanged
private readonly ILogger<HealthCheckNotifierJob> _logger;
private readonly HealthCheckNotificationMethodCollection _notifications;
private readonly IProfilingLogger _profilingLogger;
private readonly IEventAggregator _eventAggregator;
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> healthChecksSettings,
HealthCheckCollection healthChecks,
HealthCheckNotificationMethodCollection notifications,
ICoreScopeProvider scopeProvider,
ILogger<HealthCheckNotifierJob> logger,
IProfilingLogger profilingLogger,
ICronTabParser cronTabParser)
: this(
healthChecksSettings,
healthChecks,
notifications,
scopeProvider,
logger,
profilingLogger,
cronTabParser,
StaticServiceProvider.Instance.GetRequiredService<IEventAggregator>())
{ }

/// <summary>
/// Initializes a new instance of the <see cref="HealthCheckNotifierJob" /> class.
/// </summary>
Expand All @@ -58,14 +83,16 @@ public HealthCheckNotifierJob(
ICoreScopeProvider scopeProvider,
ILogger<HealthCheckNotifierJob> logger,
IProfilingLogger profilingLogger,
ICronTabParser cronTabParser)
ICronTabParser cronTabParser,
IEventAggregator eventAggregator)
{
_healthChecksSettings = healthChecksSettings.CurrentValue;
_healthChecks = healthChecks;
_notifications = notifications;
_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));
Expand Down Expand Up @@ -106,6 +133,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))
{
Expand Down
27 changes: 27 additions & 0 deletions src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@

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;
using Umbraco.Cms.Web.BackOffice.Controllers;
using Umbraco.Cms.Web.Common.Attributes;
using Umbraco.Cms.Web.Common.Authorization;
Expand All @@ -24,14 +28,27 @@ public class HealthCheckController : UmbracoAuthorizedJsonController
private readonly HealthCheckCollection _checks;
private readonly IList<Guid> _disabledCheckIds;
private readonly ILogger<HealthCheckController> _logger;
private readonly IEventAggregator _eventAggregator;
private readonly HealthChecksSettings _healthChecksSettings;

/// <summary>
/// Initializes a new instance of the <see cref="HealthCheckController" /> class.
/// </summary>
[Obsolete("Use constructor that accepts IEventAggregator as a parameter, scheduled for removal in V14")]
public HealthCheckController(HealthCheckCollection checks, ILogger<HealthCheckController> logger, IOptions<HealthChecksSettings> healthChecksSettings)
: this(checks, logger, healthChecksSettings, StaticServiceProvider.Instance.GetRequiredService<IEventAggregator>())
{ }

/// <summary>
/// Initializes a new instance of the <see cref="HealthCheckController" /> class.
/// </summary>
[ActivatorUtilitiesConstructor]
public HealthCheckController(HealthCheckCollection checks, ILogger<HealthCheckController> logger, IOptions<HealthChecksSettings> 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));
Expand Down Expand Up @@ -80,6 +97,16 @@ public async Task<object> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -105,7 +106,8 @@ private HealthCheckNotifierJob CreateHealthCheckNotifier(
mockScopeProvider.Object,
mockLogger.Object,
mockProfilingLogger.Object,
Mock.Of<ICronTabParser>());
Mock.Of<ICronTabParser>(),
Mock.Of<IEventAggregator>());
}

private void VerifyNotificationsNotSent() => VerifyNotificationsSentTimes(Times.Never());
Expand Down

0 comments on commit c0e0e7b

Please sign in to comment.