Fixed: Prevent two TypeExclusive commands running at once

The check was bypassed if a disk access command was running at the
same time.
This commit is contained in:
ta264 2019-07-14 21:29:01 +01:00
commit da2b36514a
2 changed files with 56 additions and 43 deletions

View file

@ -88,6 +88,25 @@ namespace NzbDrone.Core.Test.Messaging.Commands
command.Should().BeNull(); command.Should().BeNull();
} }
[Test]
public void should_not_return_type_exclusive_command_if_another_and_disk_access_command_running()
{
GivenStartedTypeExclusiveCommand();
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().BeNull();
}
[Test] [Test]
public void should_return_type_exclusive_command_if_another_not_running() public void should_return_type_exclusive_command_if_another_not_running()
{ {

View file

@ -134,59 +134,53 @@ namespace NzbDrone.Core.Messaging.Commands
.Select(x => x.Body.Name) .Select(x => x.Body.Name)
.ToList(); .ToList();
var localItem = _items.Where(c => var queuedCommands = _items.Where(c => c.Status == CommandStatus.Queued);
{
// 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
// instead, but that will allow other tasks to execute whiule waiting for disk access.
if (startedCommands.Any(x => x.Body.RequiresDiskAccess))
{
return c.Status == CommandStatus.Queued &&
!c.Body.RequiresDiskAccess;
}
// If an executing command is TypeExclusive don't return a command with same type if (startedCommands.Any(x => x.Body.RequiresDiskAccess))
if (startedCommands.Any(x => x.Body.IsTypeExclusive)) { {
return c.Status == CommandStatus.Queued && !exclusiveTypes.Any(x => x == c.Body.Name); queuedCommands = queuedCommands.Where(c => !c.Body.RequiresDiskAccess);
} }
return c.Status == CommandStatus.Queued; if (startedCommands.Any(x => x.Body.IsTypeExclusive))
}) {
.OrderByDescending(c => c.Priority) queuedCommands = queuedCommands.Where(c => !exclusiveTypes.Any(x => x == c.Body.Name));
.ThenBy(c => c.QueuedAt) }
.FirstOrDefault();
// Nothing queued that meets the requirements var localItem = queuedCommands.OrderByDescending(c => c.Priority)
if (localItem == null) .ThenBy(c => c.QueuedAt)
{ .FirstOrDefault();
rval = false;
}
// If any executing command is exclusive don't want return another command until it completes. // Nothing queued that meets the requirements
else if (startedCommands.Any(c => c.Body.IsExclusive)) if (localItem == null)
{ {
rval = false; rval = false;
} }
// If the next command to execute is exclusive wait for executing commands to complete. // If any executing command is exclusive don't want return another command until it completes.
// This will prevent other tasks from starting so the exclusive task executes in the order it should. else if (startedCommands.Any(c => c.Body.IsExclusive))
else if (localItem.Body.IsExclusive && startedCommands.Any()) {
{ rval = false;
rval = false; }
}
// A command ready to execute // If the next command to execute is exclusive wait for executing commands to complete.
else // This will prevent other tasks from starting so the exclusive task executes in the order it should.
{ else if (localItem.Body.IsExclusive && startedCommands.Any())
localItem.StartedAt = DateTime.UtcNow; {
localItem.Status = CommandStatus.Started; rval = false;
}
item = localItem; // A command ready to execute
} else
{
localItem.StartedAt = DateTime.UtcNow;
localItem.Status = CommandStatus.Started;
item = localItem;
} }
} }
}
return rval; return rval;
}
} }
}
} }