From 0e7a22dc952688e22eeae94bc8ca21f9dc1b7ea9 Mon Sep 17 00:00:00 2001 From: Qstick Date: Sun, 31 Dec 2017 15:24:41 -0500 Subject: [PATCH] New: Run missing root folder health check when an import is successful --- .../HealthCheck/CheckOnAttribute.cs | 12 +++++- .../HealthCheck/Checks/RootFolderCheck.cs | 3 ++ .../HealthCheck/EventDrivenHealthCheck.cs | 14 +++++++ .../HealthCheck/HealthCheckService.cs | 37 ++++++++++++++++--- .../Events/TrackImportFailedEvent.cs | 29 +++++++++++++++ .../MediaFiles/TrackFileMovingService.cs | 4 +- .../TrackImport/ImportApprovedTracks.cs | 2 + src/NzbDrone.Core/NzbDrone.Core.csproj | 2 + 8 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 src/NzbDrone.Core/HealthCheck/EventDrivenHealthCheck.cs create mode 100644 src/NzbDrone.Core/MediaFiles/Events/TrackImportFailedEvent.cs diff --git a/src/NzbDrone.Core/HealthCheck/CheckOnAttribute.cs b/src/NzbDrone.Core/HealthCheck/CheckOnAttribute.cs index a40aee50e..dd1dcb3be 100644 --- a/src/NzbDrone.Core/HealthCheck/CheckOnAttribute.cs +++ b/src/NzbDrone.Core/HealthCheck/CheckOnAttribute.cs @@ -1,5 +1,4 @@ using System; -using NzbDrone.Common.Messaging; namespace NzbDrone.Core.HealthCheck { @@ -7,10 +6,19 @@ namespace NzbDrone.Core.HealthCheck public class CheckOnAttribute : Attribute { public Type EventType { get; set; } + public CheckOnCondition Condition { get; set; } - public CheckOnAttribute(Type eventType) + public CheckOnAttribute(Type eventType, CheckOnCondition condition = CheckOnCondition.Always) { EventType = eventType; + Condition = condition; } } + + public enum CheckOnCondition + { + Always, + FailedOnly, + SuccessfulOnly + } } diff --git a/src/NzbDrone.Core/HealthCheck/Checks/RootFolderCheck.cs b/src/NzbDrone.Core/HealthCheck/Checks/RootFolderCheck.cs index 86a8fc4ef..edc7a7b44 100644 --- a/src/NzbDrone.Core/HealthCheck/Checks/RootFolderCheck.cs +++ b/src/NzbDrone.Core/HealthCheck/Checks/RootFolderCheck.cs @@ -1,5 +1,6 @@ using System.Linq; using NzbDrone.Common.Disk; +using NzbDrone.Core.MediaFiles.Events; using NzbDrone.Core.Music; using NzbDrone.Core.Music.Events; @@ -7,6 +8,8 @@ namespace NzbDrone.Core.HealthCheck.Checks { [CheckOn(typeof(ArtistDeletedEvent))] [CheckOn(typeof(ArtistMovedEvent))] + [CheckOn(typeof(TrackImportedEvent), CheckOnCondition.FailedOnly)] + [CheckOn(typeof(TrackImportFailedEvent), CheckOnCondition.SuccessfulOnly)] public class RootFolderCheck : HealthCheckBase { private readonly IArtistService _artistService; diff --git a/src/NzbDrone.Core/HealthCheck/EventDrivenHealthCheck.cs b/src/NzbDrone.Core/HealthCheck/EventDrivenHealthCheck.cs new file mode 100644 index 000000000..0b55c1ff2 --- /dev/null +++ b/src/NzbDrone.Core/HealthCheck/EventDrivenHealthCheck.cs @@ -0,0 +1,14 @@ +namespace NzbDrone.Core.HealthCheck +{ + public class EventDrivenHealthCheck + { + public IProvideHealthCheck HealthCheck { get; set; } + public CheckOnCondition Condition { get; set; } + + public EventDrivenHealthCheck(IProvideHealthCheck healthCheck, CheckOnCondition condition) + { + HealthCheck = healthCheck; + Condition = condition; + } + } +} diff --git a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs index b6487b492..f49caa498 100644 --- a/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs +++ b/src/NzbDrone.Core/HealthCheck/HealthCheckService.cs @@ -29,7 +29,7 @@ namespace NzbDrone.Core.HealthCheck private readonly IProvideHealthCheck[] _healthChecks; private readonly IProvideHealthCheck[] _startupHealthChecks; private readonly IProvideHealthCheck[] _scheduledHealthChecks; - private readonly Dictionary _eventDrivenHealthChecks; + private readonly Dictionary _eventDrivenHealthChecks; private readonly IEventAggregator _eventAggregator; private readonly ICacheManager _cacheManager; private readonly Logger _logger; @@ -58,10 +58,10 @@ namespace NzbDrone.Core.HealthCheck return _healthCheckResults.Values.ToList(); } - private Dictionary GetEventDrivenHealthChecks() + private Dictionary GetEventDrivenHealthChecks() { return _healthChecks - .SelectMany(h => h.GetType().GetAttributes().Select(a => Tuple.Create(a.EventType, h))) + .SelectMany(h => h.GetType().GetAttributes().Select(a => Tuple.Create(a.EventType, new EventDrivenHealthCheck(h, a.Condition)))) .GroupBy(t => t.Item1, t => t.Item2) .ToDictionary(g => g.Key, g => g.ToArray()); } @@ -111,15 +111,42 @@ namespace NzbDrone.Core.HealthCheck return; } - IProvideHealthCheck[] checks; + EventDrivenHealthCheck[] checks; if (!_eventDrivenHealthChecks.TryGetValue(message.GetType(), out checks)) { return; } + var filteredChecks = new List(); + var healthCheckResults = _healthCheckResults.Values.ToList(); + + foreach (var eventDrivenHealthCheck in checks) + { + if (eventDrivenHealthCheck.Condition == CheckOnCondition.Always) + { + filteredChecks.Add(eventDrivenHealthCheck.HealthCheck); + continue; + } + + var healthCheckType = eventDrivenHealthCheck.HealthCheck.GetType(); + + if (eventDrivenHealthCheck.Condition == CheckOnCondition.FailedOnly && + healthCheckResults.Any(r => r.Source == healthCheckType)) + { + filteredChecks.Add(eventDrivenHealthCheck.HealthCheck); + continue; + } + + if (eventDrivenHealthCheck.Condition == CheckOnCondition.SuccessfulOnly && + healthCheckResults.None(r => r.Source == healthCheckType)) + { + filteredChecks.Add(eventDrivenHealthCheck.HealthCheck); + } + } + // TODO: Add debounce - PerformHealthCheck(checks); + PerformHealthCheck(filteredChecks.ToArray()); } } } diff --git a/src/NzbDrone.Core/MediaFiles/Events/TrackImportFailedEvent.cs b/src/NzbDrone.Core/MediaFiles/Events/TrackImportFailedEvent.cs new file mode 100644 index 000000000..6a6c0f8bf --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/Events/TrackImportFailedEvent.cs @@ -0,0 +1,29 @@ +using System; +using NzbDrone.Common.Messaging; +using NzbDrone.Core.Download; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.MediaFiles.Events +{ + public class TrackImportFailedEvent : IEvent + { + public Exception Exception { get; set; } + public LocalTrack TrackInfo { get; } + public bool NewDownload { get; } + public string DownloadClient { get; } + public string DownloadId { get; } + + public TrackImportFailedEvent(Exception exception, LocalTrack trackInfo, bool newDownload, DownloadClientItem downloadClientItem) + { + Exception = exception; + TrackInfo = trackInfo; + NewDownload = newDownload; + + if (downloadClientItem != null) + { + DownloadClient = downloadClientItem.DownloadClient; + DownloadId = downloadClientItem.DownloadId; + } + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/TrackFileMovingService.cs b/src/NzbDrone.Core/MediaFiles/TrackFileMovingService.cs index 70f9a2b6b..055a8a739 100644 --- a/src/NzbDrone.Core/MediaFiles/TrackFileMovingService.cs +++ b/src/NzbDrone.Core/MediaFiles/TrackFileMovingService.cs @@ -1,10 +1,10 @@ using NLog; -using NzbDrone.Common; using NzbDrone.Common.Disk; using NzbDrone.Common.EnsureThat; using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; using NzbDrone.Core.MediaFiles.Events; +using NzbDrone.Core.MediaFiles.TrackImport; using NzbDrone.Core.Messaging.Events; using NzbDrone.Core.Music; using NzbDrone.Core.Organizer; @@ -166,7 +166,7 @@ namespace NzbDrone.Core.MediaFiles if (!_diskProvider.FolderExists(rootFolder)) { - throw new TrackImport.RootFolderNotFoundException(string.Format("Root folder '{0}' was not found.", rootFolder)); + throw new RootFolderNotFoundException(string.Format("Root folder '{0}' was not found.", rootFolder)); } var changed = false; diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs index a9767e8b8..063b3c2ea 100644 --- a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs +++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs @@ -131,6 +131,8 @@ namespace NzbDrone.Core.MediaFiles.TrackImport catch (RootFolderNotFoundException e) { _logger.Warn(e, "Couldn't import track " + localTrack); + _eventAggregator.PublishEvent(new TrackImportFailedEvent(e, localTrack, newDownload, downloadClientItem)); + importResults.Add(new ImportResult(importDecision, "Failed to import track, Root folder missing.")); } catch (DestinationAlreadyExistsException e) diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 80dbdeed8..cf5ea55f5 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -469,6 +469,7 @@ + @@ -643,6 +644,7 @@ +