using System; using System.Collections.Generic; using System.Linq; using NLog; using NzbDrone.Common.Cache; using NzbDrone.Common.Extensions; using NzbDrone.Common.Messaging; using NzbDrone.Common.Reflection; using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.Download; using NzbDrone.Core.Indexers; using NzbDrone.Core.Lifecycle; using NzbDrone.Core.Messaging.Commands; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.ThingiProvider.Events; namespace NzbDrone.Core.HealthCheck { public interface IHealthCheckService { List Results(); } public class HealthCheckService : IHealthCheckService, IExecute, IHandleAsync, IHandleAsync { private readonly IProvideHealthCheck[] _healthChecks; private readonly IProvideHealthCheck[] _startupHealthChecks; private readonly IProvideHealthCheck[] _scheduledHealthChecks; private readonly Dictionary _eventDrivenHealthChecks; private readonly IEventAggregator _eventAggregator; private readonly ICacheManager _cacheManager; private readonly Logger _logger; private readonly ICached _healthCheckResults; public HealthCheckService(IEnumerable healthChecks, IEventAggregator eventAggregator, ICacheManager cacheManager, Logger logger) { _healthChecks = healthChecks.ToArray(); _eventAggregator = eventAggregator; _cacheManager = cacheManager; _logger = logger; _healthCheckResults = _cacheManager.GetCache(GetType()); _startupHealthChecks = _healthChecks.Where(v => v.CheckOnStartup).ToArray(); _scheduledHealthChecks = _healthChecks.Where(v => v.CheckOnSchedule).ToArray(); _eventDrivenHealthChecks = GetEventDrivenHealthChecks(); } public List Results() { return _healthCheckResults.Values.ToList(); } private Dictionary GetEventDrivenHealthChecks() { return _healthChecks .SelectMany(h => h.GetType().GetAttributes().Select(a => Tuple.Create(a.EventType, h))) .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => g.ToArray()); } private void PerformHealthCheck(IProvideHealthCheck[] healthChecks) { var results = healthChecks.Select(c => c.Check()) .ToList(); foreach (var result in results) { if (result.Type == HealthCheckResult.Ok) { _healthCheckResults.Remove(result.Source.Name); } else { _healthCheckResults.Set(result.Source.Name, result); } } _eventAggregator.PublishEvent(new HealthCheckCompleteEvent()); } public void Execute(CheckHealthCommand message) { if (message.Trigger == CommandTrigger.Manual) { PerformHealthCheck(_healthChecks); } else { PerformHealthCheck(_scheduledHealthChecks); } } public void HandleAsync(ApplicationStartedEvent message) { PerformHealthCheck(_startupHealthChecks); } public void HandleAsync(IEvent message) { if (message is HealthCheckCompleteEvent) { return; } IProvideHealthCheck[] checks; if (!_eventDrivenHealthChecks.TryGetValue(message.GetType(), out checks)) { return; } // TODO: Add debounce PerformHealthCheck(checks); } } }