diff --git a/NzbDrone.Api/Commands/CommandModule.cs b/NzbDrone.Api/Commands/CommandModule.cs index db15b223f..3f9a2e220 100644 --- a/NzbDrone.Api/Commands/CommandModule.cs +++ b/NzbDrone.Api/Commands/CommandModule.cs @@ -39,7 +39,7 @@ namespace NzbDrone.Api.Commands private Response GetAllCommands() { - return _trackCommands.AllTracked.AsResponse(); + return _trackCommands.AllTracked().AsResponse(); } } } \ No newline at end of file diff --git a/NzbDrone.Common/Cache/Cached.cs b/NzbDrone.Common/Cache/Cached.cs index eef89f317..61d4733e4 100644 --- a/NzbDrone.Common/Cache/Cached.cs +++ b/NzbDrone.Common/Cache/Cached.cs @@ -61,6 +61,19 @@ namespace NzbDrone.Common.Cache return value.Object; } + public T Remove(string key) + { + CacheItem value; + _store.TryRemove(key, out value); + + if (value == null) + { + return default(T); + } + + return value.Object; + } + public T Get(string key, Func function, TimeSpan? lifeTime = null) { Ensure.That(() => key).IsNotNullOrWhiteSpace(); @@ -81,7 +94,6 @@ namespace NzbDrone.Common.Cache return value; } - public void Clear() { _store.Clear(); diff --git a/NzbDrone.Common/Cache/ICached.cs b/NzbDrone.Common/Cache/ICached.cs index 3708b72af..7e68b395b 100644 --- a/NzbDrone.Common/Cache/ICached.cs +++ b/NzbDrone.Common/Cache/ICached.cs @@ -13,6 +13,7 @@ namespace NzbDrone.Common.Cache void Set(string key, T value, TimeSpan? lifetime = null); T Get(string key, Func function, TimeSpan? lifeTime = null); T Find(string key); + T Remove(string key); ICollection Values { get; } } diff --git a/NzbDrone.Common/Messaging/Tracking/CommandTrackingService.cs b/NzbDrone.Common/Messaging/Tracking/CommandTrackingService.cs index 29f0fc0de..5962cabd2 100644 --- a/NzbDrone.Common/Messaging/Tracking/CommandTrackingService.cs +++ b/NzbDrone.Common/Messaging/Tracking/CommandTrackingService.cs @@ -10,11 +10,11 @@ namespace NzbDrone.Common.Messaging.Tracking TrackedCommand TrackIfNew(ICommand command); TrackedCommand Completed(TrackedCommand trackedCommand, TimeSpan runtime); TrackedCommand Failed(TrackedCommand trackedCommand, Exception e); - ICollection AllTracked { get; } + List AllTracked(); Boolean ExistingCommand(ICommand command); } - public class TrackCommands : ITrackCommands + public class TrackCommands : ITrackCommands, IExecute { private readonly ICached _cache; @@ -31,7 +31,7 @@ namespace NzbDrone.Common.Messaging.Tracking } var trackedCommand = new TrackedCommand(command, CommandState.Running); - _cache.Set(command.CommandId, trackedCommand); + Store(trackedCommand); return trackedCommand; } @@ -42,7 +42,7 @@ namespace NzbDrone.Common.Messaging.Tracking trackedCommand.State = CommandState.Completed; trackedCommand.Runtime = runtime; - _cache.Set(trackedCommand.Command.CommandId, trackedCommand); + Store(trackedCommand); return trackedCommand; } @@ -53,26 +53,43 @@ namespace NzbDrone.Common.Messaging.Tracking trackedCommand.State = CommandState.Failed; trackedCommand.Exception = e; - _cache.Set(trackedCommand.Command.CommandId, trackedCommand); + Store(trackedCommand); return trackedCommand; } - public ICollection AllTracked + public List AllTracked() { - get - { - return _cache.Values; - } + return _cache.Values.ToList(); } public bool ExistingCommand(ICommand command) { - var running = AllTracked.Where(i => i.Type == command.GetType().FullName && i.State == CommandState.Running); + 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; } + + private void Store(TrackedCommand trackedCommand) + { + if (trackedCommand.Command.GetType() == typeof(TrackedCommandCleanupCommand)) + { + return; + } + + _cache.Set(trackedCommand.Command.CommandId, trackedCommand); + } + + public void Execute(TrackedCommandCleanupCommand message) + { + var old = AllTracked().Where(c => c.StateChangeTime < DateTime.UtcNow.AddMinutes(-15)); + + foreach (var trackedCommand in old) + { + _cache.Remove(trackedCommand.Command.CommandId); + } + } } } diff --git a/NzbDrone.Common/Messaging/Tracking/TrackedCommandCleanupCommand.cs b/NzbDrone.Common/Messaging/Tracking/TrackedCommandCleanupCommand.cs new file mode 100644 index 000000000..830ba7fb5 --- /dev/null +++ b/NzbDrone.Common/Messaging/Tracking/TrackedCommandCleanupCommand.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace NzbDrone.Common.Messaging.Tracking +{ + public class TrackedCommandCleanupCommand : ICommand + { + public string CommandId { get; private set; } + + public TrackedCommandCleanupCommand() + { + CommandId = HashUtil.GenerateCommandId(); + } + } +} diff --git a/NzbDrone.Common/NzbDrone.Common.csproj b/NzbDrone.Common/NzbDrone.Common.csproj index 12ed1b7a9..f980d4610 100644 --- a/NzbDrone.Common/NzbDrone.Common.csproj +++ b/NzbDrone.Common/NzbDrone.Common.csproj @@ -96,6 +96,7 @@ + diff --git a/NzbDrone.Core/Jobs/TaskManager.cs b/NzbDrone.Core/Jobs/TaskManager.cs index 83b079769..57a894629 100644 --- a/NzbDrone.Core/Jobs/TaskManager.cs +++ b/NzbDrone.Core/Jobs/TaskManager.cs @@ -4,6 +4,7 @@ using System.Linq; using NLog; using NzbDrone.Common.Messaging; using NzbDrone.Common.Messaging.Events; +using NzbDrone.Common.Messaging.Tracking; using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration.Events; using NzbDrone.Core.Indexers; @@ -48,7 +49,8 @@ namespace NzbDrone.Core.Jobs new ScheduledTask{ Interval = 12*60, TypeName = typeof(RefreshSeriesCommand).FullName}, new ScheduledTask{ Interval = 1, TypeName = typeof(DownloadedEpisodesScanCommand).FullName}, new ScheduledTask{ Interval = 60, TypeName = typeof(ApplicationUpdateCommand).FullName}, - new ScheduledTask{ Interval = 1*60, TypeName = typeof(TrimLogCommand).FullName} + new ScheduledTask{ Interval = 1*60, TypeName = typeof(TrimLogCommand).FullName}, + new ScheduledTask{ Interval = 5, TypeName = typeof(TrackedCommandCleanupCommand).FullName} }; var currentTasks = _scheduledTaskRepository.All();