diff --git a/NzbDrone.Api/Commands/CommandModule.cs b/NzbDrone.Api/Commands/CommandModule.cs index beb6fe246..db15b223f 100644 --- a/NzbDrone.Api/Commands/CommandModule.cs +++ b/NzbDrone.Api/Commands/CommandModule.cs @@ -4,7 +4,7 @@ using NzbDrone.Api.Extensions; using NzbDrone.Common.Composition; using NzbDrone.Common.Messaging; -using NzbDrone.Common.Messaging.Manager; +using NzbDrone.Common.Messaging.Tracking; namespace NzbDrone.Api.Commands { @@ -12,13 +12,13 @@ public class CommandModule : NzbDroneRestModule { private readonly IMessageAggregator _messageAggregator; private readonly IContainer _container; - private readonly IManageCommands _commandManager; + private readonly ITrackCommands _trackCommands; - public CommandModule(IMessageAggregator messageAggregator, IContainer container, IManageCommands commandManager) + public CommandModule(IMessageAggregator messageAggregator, IContainer container, ITrackCommands trackCommands) { _messageAggregator = messageAggregator; _container = container; - _commandManager = commandManager; + _trackCommands = trackCommands; Post["/"] = x => RunCommand(ReadResourceFromRequest()); Get["/"] = x => GetAllCommands(); @@ -39,7 +39,7 @@ private Response RunCommand(CommandResource resource) private Response GetAllCommands() { - return _commandManager.Items.AsResponse(); + return _trackCommands.AllTracked.AsResponse(); } } } \ No newline at end of file diff --git a/NzbDrone.Common/Messaging/Manager/CommandManager.cs b/NzbDrone.Common/Messaging/Manager/CommandManager.cs deleted file mode 100644 index 4666e9cae..000000000 --- a/NzbDrone.Common/Messaging/Manager/CommandManager.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using NzbDrone.Common.Cache; -using NzbDrone.Common.Messaging.Events; - -namespace NzbDrone.Common.Messaging.Manager -{ - public interface IManageCommands - { - ICollection Items { get; } - Boolean ExistingItem(ICommand command); - } - - public class CommandManager : IManageCommands, - IHandle, - IHandle, - IHandle - { - private readonly ICached _cache; - - public CommandManager(ICacheManger cacheManger) - { - _cache = cacheManger.GetCache(GetType()); - } - - public void Handle(CommandStartedEvent message) - { - _cache.Set(message.Command.CommandId, new CommandManagerItem(message.Command, CommandState.Running)); - } - - public void Handle(CommandCompletedEvent message) - { - _cache.Set(message.Command.CommandId, new CommandManagerItem(message.Command, CommandState.Completed)); - } - - public void Handle(CommandFailedEvent message) - { - _cache.Set(message.Command.CommandId, new CommandManagerItem(message.Command, CommandState.Failed)); - } - - public ICollection Items - { - get - { - return _cache.Values; - } - } - - public bool ExistingItem(ICommand command) - { - var running = Items.Where(i => i.Type == command.GetType().FullName && i.State == CommandState.Running); - - var result = running.Select(r => r.Command).Contains(command, new CommandEqualityComparer()); - - return result; - } - } -} diff --git a/NzbDrone.Common/Messaging/MessageAggregator.cs b/NzbDrone.Common/Messaging/MessageAggregator.cs index 30f300a70..84d16012d 100644 --- a/NzbDrone.Common/Messaging/MessageAggregator.cs +++ b/NzbDrone.Common/Messaging/MessageAggregator.cs @@ -5,7 +5,7 @@ using NLog; using NzbDrone.Common.EnsureThat; using NzbDrone.Common.Messaging.Events; -using NzbDrone.Common.Messaging.Manager; +using NzbDrone.Common.Messaging.Tracking; using NzbDrone.Common.Serializer; using NzbDrone.Common.TPL; @@ -15,14 +15,14 @@ public class MessageAggregator : IMessageAggregator { private readonly Logger _logger; private readonly IServiceFactory _serviceFactory; - private readonly IManageCommands _commandManager; + private readonly ITrackCommands _trackCommands; private readonly TaskFactory _taskFactory; - public MessageAggregator(Logger logger, IServiceFactory serviceFactory, IManageCommands commandManager) + public MessageAggregator(Logger logger, IServiceFactory serviceFactory, ITrackCommands trackCommands) { _logger = logger; _serviceFactory = serviceFactory; - _commandManager = commandManager; + _trackCommands = trackCommands; var scheduler = new LimitedConcurrencyLevelTaskScheduler(2); _taskFactory = new TaskFactory(scheduler); } @@ -87,10 +87,13 @@ public void PublishCommand(TCommand command) where TCommand : class, I _logger.Debug("{0} -> {1}", command.GetType().Name, handler.GetType().Name); var sw = Stopwatch.StartNew(); + TrackedCommand queuedCommand = null; try { - if (_commandManager.ExistingItem(command)) + queuedCommand = _trackCommands.TrackIfNew(command); + + if (queuedCommand == null) { _logger.Info("Command is already in progress: {0}", command.GetType().Name); return; @@ -99,10 +102,17 @@ public void PublishCommand(TCommand command) where TCommand : class, I PublishEvent(new CommandStartedEvent(command)); handler.Execute(command); sw.Stop(); + + _trackCommands.Completed(queuedCommand, sw.Elapsed); PublishEvent(new CommandCompletedEvent(command)); } catch (Exception e) { + if (queuedCommand != null) + { + _trackCommands.Failed(queuedCommand, e); + } + PublishEvent(new CommandFailedEvent(command, e)); throw; } diff --git a/NzbDrone.Common/Messaging/Tracking/CommandTrackingService.cs b/NzbDrone.Common/Messaging/Tracking/CommandTrackingService.cs new file mode 100644 index 000000000..29f0fc0de --- /dev/null +++ b/NzbDrone.Common/Messaging/Tracking/CommandTrackingService.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Common.Cache; + +namespace NzbDrone.Common.Messaging.Tracking +{ + public interface ITrackCommands + { + TrackedCommand TrackIfNew(ICommand command); + TrackedCommand Completed(TrackedCommand trackedCommand, TimeSpan runtime); + TrackedCommand Failed(TrackedCommand trackedCommand, Exception e); + ICollection AllTracked { get; } + Boolean ExistingCommand(ICommand command); + } + + public class TrackCommands : ITrackCommands + { + private readonly ICached _cache; + + public TrackCommands(ICacheManger cacheManger) + { + _cache = cacheManger.GetCache(GetType()); + } + + public TrackedCommand TrackIfNew(ICommand command) + { + if (ExistingCommand(command)) + { + return null; + } + + var trackedCommand = new TrackedCommand(command, CommandState.Running); + _cache.Set(command.CommandId, trackedCommand); + + return trackedCommand; + } + + public TrackedCommand Completed(TrackedCommand trackedCommand, TimeSpan runtime) + { + trackedCommand.StateChangeTime = DateTime.UtcNow; + trackedCommand.State = CommandState.Completed; + trackedCommand.Runtime = runtime; + + _cache.Set(trackedCommand.Command.CommandId, trackedCommand); + + return trackedCommand; + } + + public TrackedCommand Failed(TrackedCommand trackedCommand, Exception e) + { + trackedCommand.StateChangeTime = DateTime.UtcNow; + trackedCommand.State = CommandState.Failed; + trackedCommand.Exception = e; + + _cache.Set(trackedCommand.Command.CommandId, trackedCommand); + + return trackedCommand; + } + + public ICollection AllTracked + { + get + { + return _cache.Values; + } + } + + public bool ExistingCommand(ICommand command) + { + var running = AllTracked.Where(i => i.Type == command.GetType().FullName && i.State == CommandState.Running); + + var result = running.Select(r => r.Command).Contains(command, new CommandEqualityComparer()); + + return result; + } + } +} diff --git a/NzbDrone.Common/Messaging/Manager/CommandManagerItem.cs b/NzbDrone.Common/Messaging/Tracking/TrackedCommand.cs similarity index 55% rename from NzbDrone.Common/Messaging/Manager/CommandManagerItem.cs rename to NzbDrone.Common/Messaging/Tracking/TrackedCommand.cs index ddfca397b..41f983d13 100644 --- a/NzbDrone.Common/Messaging/Manager/CommandManagerItem.cs +++ b/NzbDrone.Common/Messaging/Tracking/TrackedCommand.cs @@ -1,18 +1,22 @@ using System; -namespace NzbDrone.Common.Messaging.Manager +namespace NzbDrone.Common.Messaging.Tracking { - public class CommandManagerItem + public class TrackedCommand { public String Type { get; private set; } public ICommand Command { get; private set; } public CommandState State { get; set; } + public DateTime StateChangeTime { get; set; } + public TimeSpan Runtime { get; set; } + public Exception Exception { get; set; } - public CommandManagerItem(ICommand command, CommandState state) + public TrackedCommand(ICommand command, CommandState state) { Type = command.GetType().FullName; Command = command; State = state; + StateChangeTime = DateTime.UtcNow; } } diff --git a/NzbDrone.Common/NzbDrone.Common.csproj b/NzbDrone.Common/NzbDrone.Common.csproj index 105c14d22..12ed1b7a9 100644 --- a/NzbDrone.Common/NzbDrone.Common.csproj +++ b/NzbDrone.Common/NzbDrone.Common.csproj @@ -92,8 +92,8 @@ - - + +