/// <summary>Try to complete the command async result for the given commandId.
 /// </summary>
 /// <param name="commandId">The commandId.</param>
 /// <param name="aggregateRootId">The id of the aggregate which was created or updated by the command.</param>
 /// <param name="errorInfo">The error info if the command execution has any error.</param>
 public void TryComplete(Guid commandId, string aggregateRootId, ErrorInfo errorInfo)
 {
     CommandAsyncResult commandAsyncResult;
     if (!_commandAsyncResultDict.TryRemove(commandId, out commandAsyncResult))
     {
         return;
     }
     _retryService.TryAction("TryCompleteCommandAsyncResult", () => commandAsyncResult.Complete(aggregateRootId, errorInfo), 3, null);
 }
 public void SetConcurrentException(ErrorInfo errorInfo)
 {
     if (errorInfo == null)
     {
         throw new ArgumentNullException("errorInfo");
     }
     if (!(errorInfo.Exception is ConcurrentException))
     {
         throw new InvalidOperationException(string.Format("Unknown exception {0} cannot be set as concurrent exception.", errorInfo.Exception.GetType().Name));
     }
     HasConcurrentException = true;
     ErrorInfo = errorInfo;
 }
        /// <summary>Complete the command execution async result.
        /// </summary>
        /// <param name="aggregateRootId"></param>
        /// <param name="errorInfo"></param>
        public void Complete(string aggregateRootId, ErrorInfo errorInfo)
        {
            IsCompleted = true;
            AggregateRootId = aggregateRootId;
            ErrorInfo = errorInfo;

            if (_waitHandle != null)
            {
                _waitHandle.Set();
            }
            else if (_callback != null)
            {
                _callback(this);
            }
        }
        public void RetryCommand(CommandInfo commandInfo, ErrorInfo errorInfo, ActionInfo retrySuccessCallbackAction)
        {
            if (_retryCommandQueue == null)
            {
                _retryCommandQueue = Configuration.Instance.GetRetryCommandQueue();
            }
            var command = commandInfo.Command;

            Action<CommandInfo, ActionInfo> actionAfterCommandRetried = (currentCommandInfo, callbackActionInfo) =>
            {
                currentCommandInfo.IncreaseRetriedCount();
                _logger.InfoFormat("Sent {0} to command retry queue for {1} time.", currentCommandInfo.Command.GetType().Name, currentCommandInfo.RetriedCount);
                callbackActionInfo.Action(callbackActionInfo.Data);
            };

            if (commandInfo.RetriedCount < command.RetryCount)
            {
                if (_retryService.TryAction("TryEnqueueCommand", () => TryEnqueueCommand(command), 2))
                {
                    actionAfterCommandRetried(commandInfo, retrySuccessCallbackAction);
                }
                else
                {
                    _retryService.RetryInQueue(
                        new ActionInfo(
                            "TryEnqueueCommand",
                            (obj) => TryEnqueueCommand(obj as ICommand),
                            command,
                            new ActionInfo(
                                "TryEnqueueCommandFinishedAction",
                                (obj) =>
                                {
                                    var data = obj as dynamic;
                                    var currentCommandInfo = data.CommandInfo as CommandInfo;
                                    var callbackActionInfo = data.Callback as ActionInfo;
                                    actionAfterCommandRetried(currentCommandInfo, callbackActionInfo);
                                    return true;
                                },
                                new { CommandInfo = commandInfo, Callback = retrySuccessCallbackAction },
                                null)));
                }
            }
            else
            {
                _commandAsyncResultManager.TryComplete(commandInfo.Command.Id, errorInfo.ErrorMessage, errorInfo.Exception);
            }
        }
        /// <summary>Retry the given command.
        /// </summary>
        /// <param name="commandInfo"></param>
        /// <param name="eventStream"></param>
        /// <param name="errorInfo"></param>
        /// <param name="retrySuccessCallbackAction"></param>
        public void RetryCommand(CommandInfo commandInfo, EventStream eventStream, ErrorInfo errorInfo, Action retrySuccessCallbackAction)
        {
            if (_retryCommandQueue == null)
            {
                _retryCommandQueue = Configuration.Instance.GetRetryCommandQueue();
            }
            var command = commandInfo.Command;

            if (commandInfo.RetriedCount < command.RetryCount)
            {
                _retryService.TryAction("TryEnqueueCommand", () => TryEnqueueCommand(commandInfo), 3, retrySuccessCallbackAction);
            }
            else
            {
                _commandAsyncResultManager.TryComplete(command.Id, eventStream.AggregateRootId, errorInfo);
                _logger.InfoFormat("{0} retried count reached to its max retry count {1}.", command.GetType().Name, command.RetryCount);
                if (retrySuccessCallbackAction != null)
                {
                    retrySuccessCallbackAction();
                }
            }
        }
 public RollbackTransferOutRequested(Guid processId, TransferInfo transferInfo, ErrorInfo errorInfo)
     : base(processId, processId, transferInfo)
 {
     ErrorInfo = errorInfo;
 }
        public MessageExecuteResult Execute(ICommand command)
        {
            var executeResult = MessageExecuteResult.None;
            var errorInfo = new ErrorInfo();

            var commandHandler = _commandHandlerProvider.GetCommandHandler(command);
            if (commandHandler == null)
            {
                var errorMessage = string.Format("Command handler not found for {0}", command.GetType().FullName);
                _logger.Fatal(errorMessage);
                _commandAsyncResultManager.TryComplete(command.Id, errorMessage, null);
                return MessageExecuteResult.Executed;
            }

            var submitResult = SubmitResult.None;
            AggregateRoot dirtyAggregate = null;

            try
            {
                _trackingContext.Clear();
                _processingCommandCache.Add(command);
                commandHandler.Handle(_commandContext, command);
                dirtyAggregate = GetDirtyAggregate(_trackingContext);
                if (dirtyAggregate != null)
                {
                    submitResult = SubmitChanges(dirtyAggregate, BuildEventStream(dirtyAggregate, command), command, errorInfo);
                }
            }
            catch (Exception ex)
            {
                var commandHandlerType = commandHandler.GetInnerCommandHandler().GetType();
                errorInfo.ErrorMessage = string.Format("Exception raised when {0} handling {1}, command id:{2}.", commandHandlerType.Name, command.GetType().Name, command.Id);
                errorInfo.Exception = ex;
                _logger.Error(errorInfo.ErrorMessage, ex);
            }
            finally
            {
                _trackingContext.Clear();
                _processingCommandCache.TryRemove(command.Id);

                if (dirtyAggregate == null)
                {
                    _commandAsyncResultManager.TryComplete(command.Id, errorInfo.ErrorMessage, errorInfo.Exception);
                    executeResult = MessageExecuteResult.Executed;
                }
                else
                {
                    if (submitResult == SubmitResult.None ||
                        submitResult == SubmitResult.Success ||
                        submitResult == SubmitResult.SynchronizerFailed)
                    {
                        _commandAsyncResultManager.TryComplete(command.Id, errorInfo.ErrorMessage, errorInfo.Exception);
                        executeResult = MessageExecuteResult.Executed;
                    }
                    else if (submitResult == SubmitResult.Retried)
                    {
                        executeResult = MessageExecuteResult.Executed;
                    }
                    else if (submitResult == SubmitResult.PublishFailed || submitResult == SubmitResult.Failed)
                    {
                        executeResult = MessageExecuteResult.Failed;
                    }
                }
            }

            return executeResult;
        }
        private bool TryCallSynchronizersBeforeEventPersisting(IEnumerable<IEventPersistenceSynchronizer> synchronizers, EventStream eventStream, ErrorInfo errorInfo)
        {
            if (synchronizers != null && synchronizers.Count() > 0)
            {
                foreach (var synchronizer in synchronizers)
                {
                    try
                    {
                        synchronizer.OnBeforePersisting(eventStream);
                    }
                    catch (Exception ex)
                    {
                        var commandInfo = _processingCommandCache.Get(eventStream.CommandId);
                        errorInfo.Exception = ex;
                        errorInfo.ErrorMessage = string.Format(
                            "Exception raised when calling synchronizer's OnBeforePersisting method. synchronizer:{0}, command:{1}, event stream:{2}",
                            synchronizer.GetType().Name,
                            commandInfo.Command.GetType().Name,
                            eventStream.GetStreamInformation());
                        _logger.Error(errorInfo.ErrorMessage, ex);
                        return false;
                    }
                }
            }

            return true;
        }
        private SubmitResult SubmitChanges(AggregateRoot aggregateRoot, EventStream eventStream, ICommand command, ErrorInfo errorInfo)
        {
            var submitResult = SubmitResult.None;

            var synchronizers = _eventPersistenceSynchronizerProvider.GetSynchronizers(eventStream);
            var success = TryCallSynchronizersBeforeEventPersisting(synchronizers, eventStream, errorInfo);
            if (!success)
            {
                return SubmitResult.SynchronizerFailed;
            }

            var persistResult = PersistResult.None;
            try
            {
                _eventStore.Append(eventStream);
                persistResult = PersistResult.Success;
            }
            catch (Exception ex)
            {
                persistResult = ProcessException(ex, eventStream, errorInfo);
            }

            if (persistResult == PersistResult.Success)
            {
                TryRefreshMemoryCache(aggregateRoot, eventStream);
                TryCallSynchronizersAfterEventPersisted(synchronizers, eventStream);
                if (TryPublishEventStream(eventStream))
                {
                    submitResult = SubmitResult.Success;
                }
                else
                {
                    submitResult = SubmitResult.PublishFailed;
                }
            }
            else if (persistResult == PersistResult.Retried)
            {
                submitResult = SubmitResult.Retried;
            }
            else if (persistResult == PersistResult.Failed)
            {
                submitResult = SubmitResult.Failed;
            }

            return submitResult;
        }
        private PersistResult ProcessException(Exception exception, EventStream eventStream, ErrorInfo errorInfo)
        {
            if (exception is ConcurrentException)
            {
                if (IsEventStreamCommitted(eventStream))
                {
                    return PersistResult.Success;
                }

                var commandInfo = _processingCommandCache.Get(eventStream.CommandId);

                _logger.Error(string.Format(
                    "Concurrent exception raised when persisting event stream, command:{0}, event stream:{1}",
                    commandInfo.Command.GetType().Name,
                    eventStream.GetStreamInformation()), exception);

                _retryCommandService.RetryCommand(commandInfo, exception);

                return PersistResult.Retried;
            }
            else
            {
                var commandInfo = _processingCommandCache.Get(eventStream.CommandId);
                _logger.Error(string.Format(
                    "Exception raised when persisting event stream, command:{0}, event stream:{1}",
                    commandInfo.Command.GetType().Name,
                    eventStream.GetStreamInformation()), exception);
                return PersistResult.Failed;
            }
        }
 public TransferProcessResult(bool isSuccess, ErrorInfo errorInfo)
 {
     IsSuccess = isSuccess;
     ErrorInfo = errorInfo;
 }