Netcore: Health check notifier hosted service (#9295)
* Implemented health check notifier as a hosted service. Added validation to health check settings. * Registered health check notifier as a hosted service. Modified health check nested settings to use concrete classes to align with other configuration models. * Resolved issues with email sending using development server. * PR review comments and fixed failing unit test. * Changed period and delay millisecond and hourly values to TimeSpans. Changed configuration of first run time for health check notifications to use H:mm format. * Set up SecureSocketOptions as a locally defined enum. * Tightened up time format validation to verify input is an actual time (with hours and minutes only) and not a timespan. * Aligned naming and namespace of health check configuration related classes with other configuration classes. * Created constants for hex colors used in formatting health check results as HTML. * Revert "Tightened up time format validation to verify input is an actual time (with hours and minutes only) and not a timespan." This reverts commit f9bb8a7a825bcb58146879f18b47922e09453e2d. * Renamed method to be clear validation is of a TimeSpan and not a time. Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models
|
||||
{
|
||||
public class DisabledHealthCheckSettings
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public DateTime DisabledOn { get; set; }
|
||||
|
||||
public int DisabledBy { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models.Extensions
|
||||
{
|
||||
public static class HealthCheckSettingsExtensions
|
||||
{
|
||||
public static TimeSpan GetNotificationDelay(this HealthChecksSettings settings, DateTime now, TimeSpan defaultDelay)
|
||||
{
|
||||
// If first run time not set, start with just small delay after application start.
|
||||
var firstRunTime = settings.Notification.FirstRunTime;
|
||||
if (string.IsNullOrEmpty(firstRunTime))
|
||||
{
|
||||
return defaultDelay;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise start at scheduled time.
|
||||
var delay = TimeSpan.FromMinutes(now.PeriodicMinutesFrom(firstRunTime));
|
||||
return (delay < defaultDelay)
|
||||
? defaultDelay
|
||||
: delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.HealthCheck;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models
|
||||
{
|
||||
public class HealthChecksNotificationMethodSettings
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
public HealthCheckNotificationVerbosity Verbosity { get; set; } = HealthCheckNotificationVerbosity.Summary;
|
||||
|
||||
public bool FailureOnly { get; set; } = false;
|
||||
|
||||
public IDictionary<string, string> Settings { get; set; } = new Dictionary<string, string>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models
|
||||
{
|
||||
public class HealthChecksNotificationSettings
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
public string FirstRunTime { get; set; } = string.Empty;
|
||||
|
||||
public TimeSpan Period { get; set; } = TimeSpan.FromHours(24);
|
||||
|
||||
public IDictionary<string, HealthChecksNotificationMethodSettings> NotificationMethods { get; set; } = new Dictionary<string, HealthChecksNotificationMethodSettings>();
|
||||
|
||||
public IEnumerable<DisabledHealthCheckSettings> DisabledChecks { get; set; } = Enumerable.Empty<DisabledHealthCheckSettings>();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.HealthCheck;
|
||||
using Umbraco.Core.HealthCheck.Checks;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models
|
||||
{
|
||||
public class HealthChecksSettings
|
||||
{
|
||||
public IEnumerable<DisabledHealthCheck> DisabledChecks { get; set; } = Enumerable.Empty<DisabledHealthCheck>();
|
||||
public IEnumerable<DisabledHealthCheckSettings> DisabledChecks { get; set; } = Enumerable.Empty<DisabledHealthCheckSettings>();
|
||||
|
||||
public HealthCheckNotificationSettings NotificationSettings { get; set; } = new HealthCheckNotificationSettings();
|
||||
|
||||
public class HealthCheckNotificationSettings
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
public string FirstRunTime { get; set; }
|
||||
|
||||
public int PeriodInHours { get; set; } = 24;
|
||||
|
||||
public IReadOnlyDictionary<string, INotificationMethod> NotificationMethods { get; set; } = new Dictionary<string, INotificationMethod>();
|
||||
|
||||
public IEnumerable<DisabledHealthCheck> DisabledChecks { get; set; } = Enumerable.Empty<DisabledHealthCheck>();
|
||||
}
|
||||
public HealthChecksNotificationSettings Notification { get; set; } = new HealthChecksNotificationSettings();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,22 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net.Mail;
|
||||
using Umbraco.Core.Configuration.Models.Validation;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Matches MailKit.Security.SecureSocketOptions and defined locally to avoid having to take
|
||||
/// thi
|
||||
/// </summary>
|
||||
public enum SecureSocketOptions
|
||||
{
|
||||
None = 0,
|
||||
Auto = 1,
|
||||
SslOnConnect = 2,
|
||||
StartTls = 3,
|
||||
StartTlsWhenAvailable = 4
|
||||
}
|
||||
|
||||
public class SmtpSettings : ValidatableEntryBase
|
||||
{
|
||||
[Required]
|
||||
@@ -15,6 +27,8 @@ namespace Umbraco.Core.Configuration.Models
|
||||
|
||||
public int Port { get; set; }
|
||||
|
||||
public SecureSocketOptions SecureSocketOptions { get; set; } = SecureSocketOptions.Auto;
|
||||
|
||||
public string PickupDirectoryLocation { get; set; }
|
||||
|
||||
public SmtpDeliveryMethod DeliveryMethod { get; set; } = SmtpDeliveryMethod.Network;
|
||||
|
||||
@@ -41,5 +41,18 @@ namespace Umbraco.Core.Configuration.Models.Validation
|
||||
message = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ValidateOptionalTime(string configPath, string value, out string message)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(value) && !value.IsValidTimeSpan())
|
||||
{
|
||||
message = $"Configuration entry {configPath} contains an invalid time value.";
|
||||
return false;
|
||||
}
|
||||
|
||||
message = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core.Macros;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models.Validation
|
||||
{
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Umbraco.Core.Configuration.Models.Validation
|
||||
{
|
||||
public class HealthChecksSettingsValidator : ConfigurationValidatorBase, IValidateOptions<HealthChecksSettings>
|
||||
{
|
||||
public ValidateOptionsResult Validate(string name, HealthChecksSettings options)
|
||||
{
|
||||
if (!ValidateNotificationFirstRunTime(options.Notification.FirstRunTime, out var message))
|
||||
{
|
||||
return ValidateOptionsResult.Fail(message);
|
||||
}
|
||||
|
||||
return ValidateOptionsResult.Success;
|
||||
}
|
||||
|
||||
private bool ValidateNotificationFirstRunTime(string value, out string message)
|
||||
{
|
||||
return ValidateOptionalTime($"{Constants.Configuration.ConfigHealthChecks}:{nameof(HealthChecksSettings.Notification)}:{nameof(HealthChecksSettings.Notification.FirstRunTime)}", value, out message);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user