New: Don't Execute Certain Command Types In Parallel (#855)

pull/857/head
Qstick 5 years ago committed by GitHub
parent b4fc4e88a5
commit 659844eeba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,175 @@
using FluentAssertions;
using NUnit.Framework;
using NzbDrone.Core.Download;
using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Test.Framework;
using Moq;
using System.Collections.Generic;
using System.Linq;
using FizzWare.NBuilder;
using NzbDrone.Core.ImportLists;
using NzbDrone.Core.Update.Commands;
using NzbDrone.Core.Music.Commands;
namespace NzbDrone.Core.Test.Messaging.Commands
{
[TestFixture]
public class CommandQueueFixture : CoreTest<CommandQueue>
{
private void GivenStartedDiskCommand()
{
var commandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "CheckForFinishedDownload")
.With(c => c.Body = new CheckForFinishedDownloadCommand())
.With(c => c.Status = CommandStatus.Started)
.Build();
Subject.Add(commandModel);
}
private void GivenStartedTypeExclusiveCommand()
{
var commandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "ImportListSync")
.With(c => c.Body = new ImportListSyncCommand())
.With(c => c.Status = CommandStatus.Started)
.Build();
Subject.Add(commandModel);
}
private void GivenStartedExclusiveCommand()
{
var commandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "ApplicationUpdate")
.With(c => c.Body = new ApplicationUpdateCommand())
.With(c => c.Status = CommandStatus.Started)
.Build();
Subject.Add(commandModel);
}
[Test]
public void should_not_return_disk_access_command_if_another_running()
{
GivenStartedDiskCommand();
var newCommandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "CheckForFinishedDownload")
.With(c => c.Body = new CheckForFinishedDownloadCommand())
.Build();
Subject.Add(newCommandModel);
Subject.TryGet(out var command);
command.Should().BeNull();
}
[Test]
public void should_not_return_type_exclusive_command_if_another_running()
{
GivenStartedTypeExclusiveCommand();
var newCommandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "ImportListSync")
.With(c => c.Body = new ImportListSyncCommand())
.Build();
Subject.Add(newCommandModel);
Subject.TryGet(out var command);
command.Should().BeNull();
}
[Test]
public void should_return_type_exclusive_command_if_another_not_running()
{
GivenStartedDiskCommand();
var newCommandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "ImportListSync")
.With(c => c.Body = new ImportListSyncCommand())
.Build();
Subject.Add(newCommandModel);
Subject.TryGet(out var command);
command.Should().NotBeNull();
command.Status.Should().Be(CommandStatus.Started);
}
[Test]
public void should_return_regular_command_if_type_exclusive_command_running()
{
GivenStartedTypeExclusiveCommand();
var newCommandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "RefreshArtist")
.With(c => c.Body = new RefreshArtistCommand())
.Build();
Subject.Add(newCommandModel);
Subject.TryGet(out var command);
command.Should().NotBeNull();
command.Status.Should().Be(CommandStatus.Started);
}
[Test]
public void should_not_return_exclusive_command_if_any_running()
{
GivenStartedDiskCommand();
var newCommandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "ApplicationUpdate")
.With(c => c.Body = new ApplicationUpdateCommand())
.Build();
Subject.Add(newCommandModel);
Subject.TryGet(out var command);
command.Should().BeNull();
}
[Test]
public void should_not_return_any_command_if_exclusive_running()
{
GivenStartedExclusiveCommand();
var newCommandModel = Builder<CommandModel>
.CreateNew()
.With(c => c.Name = "RefreshArtist")
.With(c => c.Body = new RefreshArtistCommand())
.Build();
Subject.Add(newCommandModel);
Subject.TryGet(out var command);
command.Should().BeNull();
}
[Test]
public void should_return_null_if_nothing_queued()
{
GivenStartedDiskCommand();
Subject.TryGet(out var command);
command.Should().BeNull();
}
}
}

@ -265,6 +265,7 @@
<Compile Include="MediaFiles\TrackImport\Specifications\UpgradeSpecificationFixture.cs" />
<Compile Include="MediaFiles\ImportApprovedTracksFixture.cs" />
<Compile Include="MediaFiles\MediaFileRepositoryFixture.cs" />
<Compile Include="Messaging\Commands\CommandQueueFixture.cs" />
<Compile Include="Messaging\Commands\CommandQueueManagerFixture.cs" />
<Compile Include="MetadataSource\MetadataRequestBuilderFixture.cs" />
<Compile Include="MetadataSource\SkyHook\SkyHookProxySearchFixture.cs" />

@ -17,6 +17,8 @@ namespace NzbDrone.Core.ImportLists
public override bool SendUpdatesToClient => true;
public override bool IsTypeExclusive => true;
public override bool UpdateScheduledTask => !DefinitionId.HasValue;
}
}

@ -24,6 +24,8 @@ namespace NzbDrone.Core.Messaging.Commands
public virtual bool RequiresDiskAccess => false;
public virtual bool IsExclusive => false;
public virtual bool IsTypeExclusive => false;
public string Name { get; private set; }
public DateTime? LastExecutionTime { get; set; }
public CommandTrigger Trigger { get; set; }

@ -130,7 +130,11 @@ namespace NzbDrone.Core.Messaging.Commands
var startedCommands = _items.Where(c => c.Status == CommandStatus.Started)
.ToList();
var localItem = _items.Where(c =>
var exclusiveTypes = startedCommands.Where(x => x.Body.IsTypeExclusive)
.Select(x => x.Body.Name)
.ToList();
var localItem = _items.Where(c =>
{
// If an executing command requires disk access don't return a command that
// requires disk access. A lower priority or later queued task could be returned
@ -141,6 +145,11 @@ namespace NzbDrone.Core.Messaging.Commands
!c.Body.RequiresDiskAccess;
}
// If an executing command is TypeExclusive don't return a command with same type
if (startedCommands.Any(x => x.Body.IsTypeExclusive)) {
return c.Status == CommandStatus.Queued && !exclusiveTypes.Any(x => x == c.Body.Name);
}
return c.Status == CommandStatus.Queued;
})
.OrderByDescending(c => c.Priority)

Loading…
Cancel
Save