Updates health check config to work the Umbraco/Testable way

This commit is contained in:
Shannon
2017-08-02 22:32:28 +10:00
parent 6aeb1a8845
commit df287f291e
22 changed files with 281 additions and 92 deletions

View File

@@ -6,7 +6,7 @@ using System.Text;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class DisabledHealthCheckElement : ConfigurationElement, IDisabledHealthCheckElement
public class DisabledHealthCheckElement : ConfigurationElement, IDisabledHealthCheck
{
private const string IdKey = "id";
private const string DisabledOnKey = "disabledOn";

View File

@@ -4,7 +4,7 @@ using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
[ConfigurationCollection(typeof(DisabledHealthCheckElement), AddItemName = "check")]
public class DisabledHealthChecksElementCollection : ConfigurationElementCollection, IEnumerable<DisabledHealthCheckElement>
public class DisabledHealthChecksElementCollection : ConfigurationElementCollection, IEnumerable<IDisabledHealthCheck>
{
protected override ConfigurationElement CreateNewElement()
{
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration.HealthChecks
}
}
IEnumerator<DisabledHealthCheckElement> IEnumerable<DisabledHealthCheckElement>.GetEnumerator()
IEnumerator<IDisabledHealthCheck> IEnumerable<IDisabledHealthCheck>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{

View File

@@ -1,8 +1,10 @@
using System.Configuration;
using System;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class HealthCheckNotificationSettingsElement : ConfigurationElement, IHealthCheckNotificationSettingsElement
public class HealthCheckNotificationSettingsElement : ConfigurationElement, IHealthCheckNotificationSettings
{
private const string EnabledKey = "enabled";
private const string FirstRunTimeKey = "firstRunTime";
@@ -54,5 +56,30 @@ namespace Umbraco.Core.Configuration.HealthChecks
return (DisabledHealthChecksElementCollection)base[DisabledChecksKey];
}
}
bool IHealthCheckNotificationSettings.Enabled
{
get { return Enabled; }
}
string IHealthCheckNotificationSettings.FirstRunTime
{
get { return FirstRunTime; }
}
int IHealthCheckNotificationSettings.PeriodInHours
{
get { return PeriodInHours; }
}
IReadOnlyDictionary<string, INotificationMethod> IHealthCheckNotificationSettings.NotificationMethods
{
get { return NotificationMethods; }
}
IEnumerable<IDisabledHealthCheck> IHealthCheckNotificationSettings.DisabledChecks
{
get { return DisabledChecks; }
}
}
}

View File

@@ -1,8 +1,10 @@
using System.Configuration;
using System;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class HealthChecksSection : ConfigurationSection, IHealthChecksSection
public class HealthChecksSection : ConfigurationSection, IHealthChecks
{
private const string DisabledChecksKey = "disabledChecks";
private const string NotificationSettingsKey = "notificationSettings";
@@ -18,5 +20,15 @@ namespace Umbraco.Core.Configuration.HealthChecks
{
get { return ((HealthCheckNotificationSettingsElement)(base[NotificationSettingsKey])); }
}
IEnumerable<IDisabledHealthCheck> IHealthChecks.DisabledChecks
{
get { return DisabledChecks; }
}
IHealthCheckNotificationSettings IHealthChecks.NotificationSettings
{
get { return NotificationSettings; }
}
}
}

View File

@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IDisabledHealthCheckElement
public interface IDisabledHealthCheck
{
Guid Id { get; }
DateTime DisabledOn { get; }

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IHealthCheckNotificationSettings
{
bool Enabled { get; }
string FirstRunTime { get; }
int PeriodInHours { get; }
IReadOnlyDictionary<string, INotificationMethod> NotificationMethods { get; }
IEnumerable<IDisabledHealthCheck> DisabledChecks { get; }
}
}

View File

@@ -1,11 +0,0 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IHealthCheckNotificationSettingsElement
{
bool Enabled { get; }
string FirstRunTime { get; }
int PeriodInHours { get; }
NotificationMethodsElementCollection NotificationMethods { get; }
DisabledHealthChecksElementCollection DisabledChecks { get; }
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IHealthChecks
{
IEnumerable<IDisabledHealthCheck> DisabledChecks { get; }
IHealthCheckNotificationSettings NotificationSettings { get; }
}
}

View File

@@ -1,8 +0,0 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface IHealthChecksSection
{
DisabledHealthChecksElementCollection DisabledChecks { get; }
HealthCheckNotificationSettingsElement NotificationSettings { get; }
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface INotificationMethod
{
string Alias { get; }
bool Enabled { get; }
HealthCheckNotificationVerbosity Verbosity { get; }
bool FailureOnly { get; }
IReadOnlyDictionary<string, INotificationMethodSettings> Settings { get; }
}
}

View File

@@ -1,11 +0,0 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface INotificationMethodElement
{
string Alias { get; }
bool Enabled { get; }
HealthCheckNotificationVerbosity Verbosity { get; }
bool FailureOnly { get; }
NotificationMethodSettingsElementCollection Settings { get; }
}
}

View File

@@ -1,6 +1,6 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public interface INotificationMethodSettingsElement
public interface INotificationMethodSettings
{
string Key { get; }
string Value { get; }

View File

@@ -1,8 +1,10 @@
using System.Configuration;
using System;
using System.Collections.Generic;
using System.Configuration;
namespace Umbraco.Core.Configuration.HealthChecks
{
public class NotificationMethodElement : ConfigurationElement, INotificationMethodElement
public class NotificationMethodElement : ConfigurationElement, INotificationMethod
{
private const string AliasKey = "alias";
private const string EnabledKey = "enabled";
@@ -54,5 +56,30 @@ namespace Umbraco.Core.Configuration.HealthChecks
return (NotificationMethodSettingsElementCollection)base[SettingsKey];
}
}
string INotificationMethod.Alias
{
get { return Alias; }
}
bool INotificationMethod.Enabled
{
get { return Enabled; }
}
HealthCheckNotificationVerbosity INotificationMethod.Verbosity
{
get { return Verbosity; }
}
bool INotificationMethod.FailureOnly
{
get { return FailureOnly; }
}
IReadOnlyDictionary<string, INotificationMethodSettings> INotificationMethod.Settings
{
get { return Settings; }
}
}
}

View File

@@ -2,7 +2,7 @@
namespace Umbraco.Core.Configuration.HealthChecks
{
public class NotificationMethodSettingsElement : ConfigurationElement, INotificationMethodSettingsElement
public class NotificationMethodSettingsElement : ConfigurationElement, INotificationMethodSettings
{
private const string KeyKey = "key";
private const string ValueKey = "value";

View File

@@ -1,10 +1,12 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
namespace Umbraco.Core.Configuration.HealthChecks
{
[ConfigurationCollection(typeof(NotificationMethodSettingsElement), AddItemName = "add")]
public class NotificationMethodSettingsElementCollection : ConfigurationElementCollection, IEnumerable<NotificationMethodSettingsElement>
public class NotificationMethodSettingsElementCollection : ConfigurationElementCollection, IEnumerable<INotificationMethodSettings>, IReadOnlyDictionary<string, INotificationMethodSettings>
{
protected override ConfigurationElement CreateNewElement()
{
@@ -14,27 +16,65 @@ namespace Umbraco.Core.Configuration.HealthChecks
protected override object GetElementKey(ConfigurationElement element)
{
return ((NotificationMethodSettingsElement)(element)).Key;
}
}
public new NotificationMethodSettingsElement this[string key]
{
get
{
return (NotificationMethodSettingsElement)BaseGet(key);
}
}
IEnumerator<NotificationMethodSettingsElement> IEnumerable<NotificationMethodSettingsElement>.GetEnumerator()
IEnumerator<KeyValuePair<string, INotificationMethodSettings>> IEnumerable<KeyValuePair<string, INotificationMethodSettings>>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return BaseGet(i) as NotificationMethodSettingsElement;
var val = (NotificationMethodSettingsElement)BaseGet(i);
var key = (string)BaseGetKey(i);
yield return new KeyValuePair<string, INotificationMethodSettings>(key, val);
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
IEnumerator<INotificationMethodSettings> IEnumerable<INotificationMethodSettings>.GetEnumerator()
{
return GetEnumerator();
for (var i = 0; i < Count; i++)
{
yield return (NotificationMethodSettingsElement)BaseGet(i);
}
}
bool IReadOnlyDictionary<string, INotificationMethodSettings>.ContainsKey(string key)
{
return ((IReadOnlyDictionary<string, INotificationMethodSettings>)this).Keys.Any(x => x == key);
}
bool IReadOnlyDictionary<string, INotificationMethodSettings>.TryGetValue(string key, out INotificationMethodSettings value)
{
try
{
var val = (NotificationMethodSettingsElement)BaseGet(key);
value = val;
return true;
}
catch (Exception)
{
value = null;
return false;
}
}
INotificationMethodSettings IReadOnlyDictionary<string, INotificationMethodSettings>.this[string key]
{
get { return (NotificationMethodSettingsElement)BaseGet(key); }
}
IEnumerable<string> IReadOnlyDictionary<string, INotificationMethodSettings>.Keys
{
get { return BaseGetAllKeys().Cast<string>(); }
}
IEnumerable<INotificationMethodSettings> IReadOnlyDictionary<string, INotificationMethodSettings>.Values
{
get
{
for (var i = 0; i < Count; i++)
{
yield return (NotificationMethodSettingsElement)BaseGet(i);
}
}
}
}
}

View File

@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
namespace Umbraco.Core.Configuration.HealthChecks
{
[ConfigurationCollection(typeof(NotificationMethodElement), AddItemName = "notificationMethod")]
public class NotificationMethodsElementCollection : ConfigurationElementCollection, IEnumerable<NotificationMethodElement>
public class NotificationMethodsElementCollection : ConfigurationElementCollection, IEnumerable<INotificationMethod>, IReadOnlyDictionary<string, INotificationMethod>
{
protected override ConfigurationElement CreateNewElement()
{
@@ -16,26 +17,64 @@ namespace Umbraco.Core.Configuration.HealthChecks
{
return ((NotificationMethodElement)(element)).Alias;
}
new public NotificationMethodElement this[string key]
{
get
{
return (NotificationMethodElement)BaseGet(key);
}
}
IEnumerator<NotificationMethodElement> IEnumerable<NotificationMethodElement>.GetEnumerator()
IEnumerator<KeyValuePair<string, INotificationMethod>> IEnumerable<KeyValuePair<string, INotificationMethod>>.GetEnumerator()
{
for (var i = 0; i < Count; i++)
{
yield return BaseGet(i) as NotificationMethodElement;
var val = (NotificationMethodElement)BaseGet(i);
var key = (string)BaseGetKey(i);
yield return new KeyValuePair<string, INotificationMethod>(key, val);
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
IEnumerator<INotificationMethod> IEnumerable<INotificationMethod>.GetEnumerator()
{
return GetEnumerator();
for (var i = 0; i < Count; i++)
{
yield return (NotificationMethodElement)BaseGet(i);
}
}
bool IReadOnlyDictionary<string, INotificationMethod>.ContainsKey(string key)
{
return ((IReadOnlyDictionary<string, INotificationMethod>) this).Keys.Any(x => x == key);
}
bool IReadOnlyDictionary<string, INotificationMethod>.TryGetValue(string key, out INotificationMethod value)
{
try
{
var val = (NotificationMethodElement)BaseGet(key);
value = val;
return true;
}
catch (Exception)
{
value = null;
return false;
}
}
INotificationMethod IReadOnlyDictionary<string, INotificationMethod>.this[string key]
{
get { return (NotificationMethodElement)BaseGet(key); }
}
IEnumerable<string> IReadOnlyDictionary<string, INotificationMethod>.Keys
{
get { return BaseGetAllKeys().Cast<string>(); }
}
IEnumerable<INotificationMethod> IReadOnlyDictionary<string, INotificationMethod>.Values
{
get
{
for (var i = 0; i < Count; i++)
{
yield return (NotificationMethodElement)BaseGet(i);
}
}
}
}
}

View File

@@ -9,6 +9,7 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Configuration.BaseRest;
using Umbraco.Core.Configuration.Dashboard;
using Umbraco.Core.Configuration.Grid;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
@@ -52,6 +53,12 @@ namespace Umbraco.Core.Configuration
var dashboardConfig = ConfigurationManager.GetSection("umbracoConfiguration/dashBoard") as IDashboardSection;
SetDashboardSettings(dashboardConfig);
}
if (_healthChecks == null)
{
var healthCheckConfig = ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks") as IHealthChecks;
SetHealthCheckSettings(healthCheckConfig);
}
}
/// <summary>
@@ -60,18 +67,36 @@ namespace Umbraco.Core.Configuration
/// <param name="umbracoSettings"></param>
/// <param name="baseRestSettings"></param>
/// <param name="dashboardSettings"></param>
public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IBaseRestSection baseRestSettings, IDashboardSection dashboardSettings)
/// <param name="healthChecks"></param>
public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IBaseRestSection baseRestSettings, IDashboardSection dashboardSettings, IHealthChecks healthChecks)
{
SetHealthCheckSettings(healthChecks);
SetUmbracoSettings(umbracoSettings);
SetBaseRestExtensions(baseRestSettings);
SetDashboardSettings(dashboardSettings);
}
private IHealthChecks _healthChecks;
private IDashboardSection _dashboardSection;
private IUmbracoSettingsSection _umbracoSettings;
private IBaseRestSection _baseRestExtensions;
private IGridConfig _gridConfig;
/// <summary>
/// Gets the IHealthCheck config
/// </summary>
public IHealthChecks HealthCheck()
{
if (_healthChecks == null)
{
var ex = new ConfigurationErrorsException("Could not load the " + typeof(IHealthChecks) + " from config file, ensure the web.config and healthchecks.config files are formatted correctly");
LogHelper.Error<UmbracoConfig>("Config error", ex);
throw ex;
}
return _healthChecks;
}
/// <summary>
/// Gets the IDashboardSection
/// </summary>
@@ -86,14 +111,23 @@ namespace Umbraco.Core.Configuration
return _dashboardSection;
}
/// <summary>
/// Only for testing
/// </summary>
/// <param name="value"></param>
public void SetDashboardSettings(IDashboardSection value)
{
_dashboardSection = value;
}
/// <summary>
/// Only for testing
/// </summary>
/// <param name="value"></param>
internal void SetDashboardSettings(IDashboardSection value)
public void SetHealthCheckSettings(IHealthChecks value)
{
_dashboardSection = value;
_healthChecks = value;
}
/// <summary>

View File

@@ -216,11 +216,11 @@
<Compile Include="Configuration\Dashboard\SectionElement.cs" />
<Compile Include="Configuration\Dashboard\TabCollection.cs" />
<Compile Include="Configuration\Dashboard\TabElement.cs" />
<Compile Include="Configuration\HealthChecks\IDisabledHealthCheckElement.cs" />
<Compile Include="Configuration\HealthChecks\IHealthCheckNotificationSettingsElement.cs" />
<Compile Include="Configuration\HealthChecks\IHealthChecksSection.cs" />
<Compile Include="Configuration\HealthChecks\INotificationMethodElement.cs" />
<Compile Include="Configuration\HealthChecks\INotificationMethodSettingsElement.cs" />
<Compile Include="Configuration\HealthChecks\IDisabledHealthCheck.cs" />
<Compile Include="Configuration\HealthChecks\IHealthCheckNotificationSettings.cs" />
<Compile Include="Configuration\HealthChecks\IHealthChecks.cs" />
<Compile Include="Configuration\HealthChecks\INotificationMethod.cs" />
<Compile Include="Configuration\HealthChecks\INotificationMethodSettings.cs" />
<Compile Include="Configuration\HealthChecks\NotificationMethodSettingsElement.cs" />
<Compile Include="Configuration\HealthChecks\NotificationMethodElement.cs" />
<Compile Include="Configuration\HealthChecks\NotificationMethodSettingsElementCollection.cs" />

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web.Http;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Web.Editors;
@@ -20,7 +21,7 @@ namespace Umbraco.Web.HealthCheck
{
_healthCheckResolver = HealthCheckResolver.Current;
var healthCheckConfig = (HealthChecksSection)ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks");
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
_disabledCheckIds = healthCheckConfig.DisabledChecks
.Select(x => x.Id)
.ToList();

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Configuration;
using System.Reflection;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
using Umbraco.Web.HealthCheck.NotificationMethods;
@@ -55,7 +56,7 @@ namespace Umbraco.Web.HealthCheck
}
// Using alias, get related configuration
var healthCheckConfig = (HealthChecksSection)ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks");
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
var notificationMethods = healthCheckConfig.NotificationSettings.NotificationMethods;
var notificationMethod = notificationMethods[attribute.Alias];
if (notificationMethod == null)

View File

@@ -3,6 +3,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Logging;
using Umbraco.Core.Sync;
@@ -44,9 +45,9 @@ namespace Umbraco.Web.Scheduling
return false; // do NOT repeat, going down
}
using (DisposableTimer.DebugDuration<KeepAlive>(() => "Health checks executing", () => "Health checks complete"))
using (_appContext.ProfilingLogger.DebugDuration<KeepAlive>("Health checks executing", "Health checks complete"))
{
var healthCheckConfig = (HealthChecksSection)ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks");
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
// Don't notify for any checks that are disabled, nor for any disabled
// just for notifications

View File

@@ -6,6 +6,7 @@ using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.HealthChecks;
using Umbraco.Core.Logging;
using Umbraco.Web.HealthCheck;
using Umbraco.Web.Routing;
namespace Umbraco.Web.Scheduling
@@ -65,15 +66,15 @@ namespace Umbraco.Web.Scheduling
LogHelper.Debug<Scheduler>(() => "Initializing the scheduler");
var settings = UmbracoConfig.For.UmbracoSettings();
var healthCheckConfig = (HealthChecksSection)ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks");
var healthCheckConfig = UmbracoConfig.For.HealthCheck();
const int DelayMilliseconds = 60000;
const int delayMilliseconds = 60000;
var tasks = new List<IBackgroundTask>
{
new KeepAlive(_keepAliveRunner, DelayMilliseconds, 300000, e.UmbracoContext.Application),
new ScheduledPublishing(_publishingRunner, DelayMilliseconds, 60000, e.UmbracoContext.Application, settings),
new ScheduledTasks(_tasksRunner, DelayMilliseconds, 60000, e.UmbracoContext.Application, settings),
new LogScrubber(_scrubberRunner, DelayMilliseconds, LogScrubber.GetLogScrubbingInterval(settings), e.UmbracoContext.Application, settings),
new KeepAlive(_keepAliveRunner, delayMilliseconds, 300000, e.UmbracoContext.Application),
new ScheduledPublishing(_publishingRunner, delayMilliseconds, 60000, e.UmbracoContext.Application, settings),
new ScheduledTasks(_tasksRunner, delayMilliseconds, 60000, e.UmbracoContext.Application, settings),
new LogScrubber(_scrubberRunner, delayMilliseconds, LogScrubber.GetLogScrubbingInterval(settings), e.UmbracoContext.Application, settings),
};
if (healthCheckConfig.NotificationSettings.Enabled)
@@ -82,15 +83,15 @@ namespace Umbraco.Web.Scheduling
int delayInMilliseconds;
if (string.IsNullOrEmpty(healthCheckConfig.NotificationSettings.FirstRunTime))
{
delayInMilliseconds = DelayMilliseconds;
delayInMilliseconds = delayMilliseconds;
}
else
{
// Otherwise start at scheduled time
delayInMilliseconds = DateTime.Now.PeriodicMinutesFrom(healthCheckConfig.NotificationSettings.FirstRunTime) * 60 * 1000;
if (delayInMilliseconds < DelayMilliseconds)
if (delayInMilliseconds < delayMilliseconds)
{
delayInMilliseconds = DelayMilliseconds;
delayInMilliseconds = delayMilliseconds;
}
}