private void ExecuteCommand <TCommand>(TCommand command, CommandModel commandModel) where TCommand : Command { var handlerContract = typeof(IExecute <>).MakeGenericType(command.GetType()); var handler = (IExecute <TCommand>)_serviceFactory.Build(handlerContract); _logger.Trace("{0} -> {1}", command.GetType().Name, handler.GetType().Name); try { _commandQueueManager.Start(commandModel); BroadcastCommandUpdate(commandModel); if (ProgressMessageContext.CommandModel == null) { ProgressMessageContext.CommandModel = commandModel; } handler.Execute(command); _commandQueueManager.Complete(commandModel, command.CompletionMessage ?? commandModel.Message); } catch (CommandFailedException ex) { _commandQueueManager.SetMessage(commandModel, "Failed"); _commandQueueManager.Fail(commandModel, ex.Message, ex); throw; } catch (Exception ex) { _commandQueueManager.SetMessage(commandModel, "Failed"); _commandQueueManager.Fail(commandModel, "Failed", ex); throw; } finally { BroadcastCommandUpdate(commandModel); _eventAggregator.PublishEvent(new CommandExecutedEvent(commandModel)); if (ProgressMessageContext.CommandModel == commandModel) { ProgressMessageContext.CommandModel = null; } } _logger.Trace("{0} <- {1} [{2}]", command.GetType().Name, handler.GetType().Name, commandModel.Duration.ToString()); }
public List <CommandModel> PushMany <TCommand>(List <TCommand> commands) where TCommand : Command { _logger.Trace("Publishing {0} commands", commands.Count); lock (_commandQueue) { var commandModels = new List <CommandModel>(); var existingCommands = _commandQueue.QueuedOrStarted(); foreach (var command in commands) { var existing = existingCommands.FirstOrDefault(c => c.Name == command.Name && CommandEqualityComparer.Instance.Equals(c.Body, command)); if (existing != null) { continue; } var commandModel = new CommandModel { Name = command.Name, Body = command, QueuedAt = DateTime.UtcNow, Trigger = CommandTrigger.Unspecified, Priority = CommandPriority.Normal, Status = CommandStatus.Queued }; commandModels.Add(commandModel); } _repo.InsertMany(commandModels); foreach (var commandModel in commandModels) { _commandQueue.Add(commandModel); } return(commandModels); } }
public CommandModel Push <TCommand>(TCommand command, CommandPriority priority = CommandPriority.Normal, CommandTrigger trigger = CommandTrigger.Unspecified) where TCommand : Command { Ensure.That(command, () => command).IsNotNull(); _logger.Trace("Publishing {0}", command.Name); _logger.Trace("Checking if command is queued or started: {0}", command.Name); lock (_commandQueue) { var existingCommands = QueuedOrStarted(command.Name); var existing = existingCommands.FirstOrDefault(c => CommandEqualityComparer.Instance.Equals(c.Body, command)); if (existing != null) { _logger.Trace("Command is already in progress: {0}", command.Name); return(existing); } var commandModel = new CommandModel { Name = command.Name, Body = command, QueuedAt = DateTime.UtcNow, Trigger = trigger, Priority = priority, Status = CommandStatus.Queued }; _logger.Trace("Inserting new command: {0}", commandModel.Name); _repo.Insert(commandModel); _commandQueue.Add(commandModel); return(commandModel); } }
public void Fail(CommandModel command, string message, Exception e) { command.Exception = e.ToString(); Update(command, CommandStatus.Failed, message); }
public void Complete(CommandModel command, string message) { Update(command, CommandStatus.Completed, message); }
public void Start(CommandModel command) { // Marks the command as started in the DB, the queue takes care of marking it as started on it's own _logger.Trace("Marking command as started: {0}", command.Name); _repo.Start(command); }
public void SetMessage(CommandModel command, string message) { command.Message = message; }
private bool TryGet(out CommandModel item) { var rval = true; item = default(CommandModel); lock (_mutex) { if (_items.Count == 0) { rval = false; } else { var startedCommands = _items.Where(c => c.Status == CommandStatus.Started) .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 // 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); } return(c.Status == CommandStatus.Queued); }) .OrderByDescending(c => c.Priority) .ThenBy(c => c.QueuedAt) .FirstOrDefault(); // Nothing queued that meets the requirements if (localItem == null) { rval = false; } // If any executing command is exclusive don't want return another command until it completes. else if (startedCommands.Any(c => c.Body.IsExclusive)) { rval = false; } // If the next command to execute is exclusive wait for executing commands to complete. // This will prevent other tasks from starting so the exclusive task executes in the order it should. else if (localItem.Body.IsExclusive && startedCommands.Any()) { rval = false; } // A command ready to execute else { localItem.StartedAt = DateTime.UtcNow; localItem.Status = CommandStatus.Started; item = localItem; } } } return(rval); }
public CommandUpdatedEvent(CommandModel command) { Command = command; }
public void Complete(CommandModel command, string message) { Update(command, CommandStatus.Completed, message); _commandQueue.PulseAllConsumers(); }
public bool TryGet(out CommandModel item) { var rval = true; item = default(CommandModel); lock (_mutex) { if (_items.Count == 0) { rval = false; } else { var startedCommands = _items.Where(c => c.Status == CommandStatus.Started) .ToList(); var exclusiveTypes = startedCommands.Where(x => x.Body.IsTypeExclusive) .Select(x => x.Body.Name) .ToList(); var queuedCommands = _items.Where(c => c.Status == CommandStatus.Queued); if (startedCommands.Any(x => x.Body.RequiresDiskAccess)) { queuedCommands = queuedCommands.Where(c => !c.Body.RequiresDiskAccess); } if (startedCommands.Any(x => x.Body.IsTypeExclusive)) { queuedCommands = queuedCommands.Where(c => !exclusiveTypes.Any(x => x == c.Body.Name)); } var localItem = queuedCommands.OrderByDescending(c => c.Priority) .ThenBy(c => c.QueuedAt) .FirstOrDefault(); // Nothing queued that meets the requirements if (localItem == null) { rval = false; } // If any executing command is exclusive don't want return another command until it completes. else if (startedCommands.Any(c => c.Body.IsExclusive)) { rval = false; } // If the next command to execute is exclusive wait for executing commands to complete. // This will prevent other tasks from starting so the exclusive task executes in the order it should. else if (localItem.Body.IsExclusive && startedCommands.Any()) { rval = false; } // A command ready to execute else { localItem.StartedAt = DateTime.UtcNow; localItem.Status = CommandStatus.Started; item = localItem; } } } return rval; }
public void SetMessage(CommandModel command, string message) { command.Message = message; _commandCache.Set(command.Id.ToString(), command); }
public CommandExecutedEvent(CommandModel command) { Command = command; }