Esempio n. 1
0
        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());
        }
Esempio n. 2
0
        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);
            }
        }
Esempio n. 3
0
        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);
            }
        }
Esempio n. 4
0
        public void Fail(CommandModel command, string message, Exception e)
        {
            command.Exception = e.ToString();

            Update(command, CommandStatus.Failed, message);
        }
Esempio n. 5
0
 public void Complete(CommandModel command, string message)
 {
     Update(command, CommandStatus.Completed, message);
 }
Esempio n. 6
0
 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);
 }
Esempio n. 7
0
 public void SetMessage(CommandModel command, string message)
 {
     command.Message = message;
 }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
 public CommandUpdatedEvent(CommandModel command)
 {
     Command = command;
 }
Esempio n. 10
0
        public void Complete(CommandModel command, string message)
        {
            Update(command, CommandStatus.Completed, message);

            _commandQueue.PulseAllConsumers();
        }
Esempio n. 11
0
        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;
        }
Esempio n. 12
0
 public void SetMessage(CommandModel command, string message)
 {
     command.Message = message;
     _commandCache.Set(command.Id.ToString(), command);
 }
Esempio n. 13
0
 public CommandExecutedEvent(CommandModel command)
 {
     Command = command;
 }