private void HandleExceptionAsync(ProcessingCommand processingCommand, ICommandHandlerProxy commandHandler, Exception exception, int retryTimes) { var command = processingCommand.Message; _ioHelper.TryAsyncActionRecursively <AsyncTaskResult <HandledCommand> >("GetCommandAsync", () => _commandStore.GetAsync(command.Id), currentRetryTimes => HandleExceptionAsync(processingCommand, commandHandler, exception, currentRetryTimes), result => { var existingHandledCommand = result.Data; if (existingHandledCommand != null) { HandleExistingHandledCommandForExceptionAsync(processingCommand, existingHandledCommand, commandHandler, exception, 0); } else { //到这里,说明当前command执行遇到异常,然后当前command之前也没执行过,是第一次被执行。 //那就判断当前异常是否是需要被发布出去的异常,如果是,则发布该异常给所有消费者;否则,就记录错误日志; //然后,认为该command处理失败即可; var publishableException = exception as IPublishableException; if (publishableException != null) { PublishExceptionAsync(processingCommand, publishableException, 0); } else { LogCommandExecuteException(processingCommand, commandHandler, exception); NotifyCommandExecuted(processingCommand, CommandStatus.Failed, exception.GetType().Name, exception.Message); } } }, () => string.Format("[commandId:{0}]", command.Id), () => NotifyCommandExecuted(processingCommand, CommandStatus.Failed, null, "Get command async failed."), retryTimes); }
private Task HandleCommandInternal(ProcessingCommand processingCommand, ICommandHandlerProxy commandHandler, int retryTimes, TaskCompletionSource <bool> taskSource) { var command = processingCommand.Message; var commandContext = processingCommand.CommandExecuteContext; commandContext.Clear(); _ioHelper.TryAsyncActionRecursivelyWithoutResult("HandleCommandAsync", async() => { await commandHandler.HandleAsync(commandContext, command).ConfigureAwait(false); }, currentRetryTimes => HandleCommandInternal(processingCommand, commandHandler, currentRetryTimes, taskSource), async() => { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Handle command success. handlerType:{0}, commandType:{1}, commandId:{2}, aggregateRootId:{3}", commandHandler.GetInnerObject().GetType().Name, command.GetType().Name, command.Id, command.AggregateRootId); } if (commandContext.GetApplicationMessage() != null) { await CommitChangesAsync(processingCommand, true, commandContext.GetApplicationMessage(), null, new TaskCompletionSource <bool>()).ConfigureAwait(false); taskSource.SetResult(true); } else { try { await CommitAggregateChanges(processingCommand).ConfigureAwait(false); taskSource.SetResult(true); } catch (Exception ex) { _logger.Error(string.Format("Commit aggregate changes has unknown exception, handlerType:{0}, commandType:{1}, commandId:{2}, aggregateRootId:{3}", commandHandler.GetInnerObject().GetType().Name, command.GetType().Name, command.Id, command.AggregateRootId), ex); await CompleteCommand(processingCommand, CommandStatus.Failed, ex.GetType().Name, "Unknown exception caught when committing changes of command.").ConfigureAwait(false); taskSource.SetResult(true); } } }, () => string.Format("[command:[id:{0},type:{1}],handlerType:{2},aggregateRootId:{3}]", command.Id, command.GetType().Name, commandHandler.GetInnerObject().GetType().Name, command.AggregateRootId), async(ex, errorMessage) => { await HandleExceptionAsync(processingCommand, commandHandler, ex, errorMessage, 0, new TaskCompletionSource <bool>()).ConfigureAwait(false); taskSource.SetResult(true); }, retryTimes); return(taskSource.Task); }
private void LogCommandExecuteException(ProcessingCommand processingCommand, ICommandHandlerProxy commandHandler, Exception exception) { var errorMessage = string.Format("{0} raised when {1} handling {2}. commandId:{3}, aggregateRootId:{4}", exception.GetType().Name, commandHandler.GetInnerHandler().GetType().Name, processingCommand.Message.GetType().Name, processingCommand.Message.Id, processingCommand.Message.AggregateRootId); _logger.Error(errorMessage, exception); }
private void HandleCommand(ProcessingCommand processingCommand, ICommandHandlerProxy commandHandler) { var command = processingCommand.Message; //调用command handler执行当前command var handleSuccess = false; try { commandHandler.Handle(processingCommand.CommandExecuteContext, command); if (_logger.IsDebugEnabled) { _logger.DebugFormat("Handle command success. handlerType:{0}, commandType:{1}, commandId:{2}, aggregateRootId:{3}", commandHandler.GetInnerHandler().GetType().Name, command.GetType().Name, command.Id, processingCommand.Message.AggregateRootId); } handleSuccess = true; } catch (IOException ex) { _logger.Error(ex); RetryCommand(processingCommand); return; } catch (Exception ex) { HandleExceptionAsync(processingCommand, commandHandler, ex, 0); return; } //如果command执行成功,则提交执行后的结果 if (handleSuccess) { try { CommitAggregateChanges(processingCommand); } catch (Exception ex) { LogCommandExecuteException(processingCommand, commandHandler, ex); NotifyCommandExecuted(processingCommand, CommandStatus.Failed, ex.GetType().Name, "Unknown exception caught when committing changes of command."); } } }
private void HandleExceptionAsync(ProcessingCommand processingCommand, ICommandHandlerProxy commandHandler, Exception exception, int retryTimes) { var command = processingCommand.Message; _ioHelper.TryAsyncActionRecursively("FindEventByCommandIdAsync", () => _eventStore.FindAsync(command.AggregateRootId, command.Id), currentRetryTimes => HandleExceptionAsync(processingCommand, commandHandler, exception, currentRetryTimes), result => { var existingEventStream = result.Data; if (existingEventStream != null) { //这里,我们需要再重新做一遍发布事件这个操作; //之所以要这样做是因为虽然该command产生的事件已经持久化成功,但并不表示事件已经发布出去了; //因为有可能事件持久化成功了,但那时正好机器断电了,则发布事件就没有做; _eventService.PublishDomainEventAsync(processingCommand, existingEventStream); processingCommand.Mailbox.TryExecuteNextMessage(); } else { //到这里,说明当前command执行遇到异常,然后当前command之前也没执行过,是第一次被执行。 //那就判断当前异常是否是需要被发布出去的异常,如果是,则发布该异常给所有消费者; //否则,就记录错误日志,然后认为该command处理失败即可; var publishableException = exception as IPublishableException; if (publishableException != null) { PublishExceptionAsync(processingCommand, publishableException, 0); } else { LogCommandExecuteException(processingCommand, commandHandler, exception); CompleteCommand(processingCommand, CommandStatus.Failed, exception.GetType().Name, exception.Message); } } }, () => string.Format("[commandId:{0}]", command.Id), errorMessage => { _logger.Fatal(string.Format("Find event by commandId has unknown exception, the code should not be run to here, errorMessage: {0}", errorMessage)); }, retryTimes, true); }
private Task HandleExceptionAsync(ProcessingCommand processingCommand, ICommandHandlerProxy commandHandler, Exception exception, string errorMessage, int retryTimes, TaskCompletionSource <bool> taskSource) { var command = processingCommand.Message; _ioHelper.TryAsyncActionRecursively("FindEventByCommandIdAsync", () => _eventStore.FindAsync(command.AggregateRootId, command.Id), currentRetryTimes => HandleExceptionAsync(processingCommand, commandHandler, exception, errorMessage, currentRetryTimes, taskSource), async result => { var existingEventStream = result; if (existingEventStream != null) { //这里,我们需要再重新做一遍发布事件这个操作; //之所以要这样做是因为虽然该command产生的事件已经持久化成功,但并不表示事件已经发布出去了; //因为有可能事件持久化成功了,但那时正好机器断电了,则发布事件就没有做; _eventCommittingService.PublishDomainEventAsync(processingCommand, existingEventStream); taskSource.SetResult(true); } else { //到这里,说明当前command执行遇到异常,然后当前command之前也没执行过,是第一次被执行。 //那就判断当前异常是否是需要被发布出去的异常,如果是,则发布该异常给所有消费者; //否则,就记录错误日志,然后认为该command处理失败即可; var domainException = TryGetDomainException(exception); if (domainException != null) { await PublishExceptionAsync(processingCommand, domainException, 0, new TaskCompletionSource <bool>()).ConfigureAwait(false); taskSource.SetResult(true); } else { await CompleteCommand(processingCommand, CommandStatus.Failed, exception.GetType().Name, exception != null ? exception.Message : errorMessage).ConfigureAwait(false); taskSource.SetResult(true); } } }, () => string.Format("[command:[id:{0},type:{1}],handlerType:{2},aggregateRootId:{3}]", command.Id, command.GetType().Name, commandHandler.GetInnerObject().GetType().Name, command.AggregateRootId), null, retryTimes, true); return(taskSource.Task); }
private void HandleExceptionAsync(ProcessingCommand processingCommand, ICommandHandlerProxy commandHandler, Exception exception, int retryTimes) { var command = processingCommand.Message; _ioHelper.TryAsyncActionRecursively <AsyncTaskResult <DomainEventStream> >("FindEventStreamByCommandIdAsync", () => _eventStore.FindAsync(command.AggregateRootId, command.Id), currentRetryTimes => HandleExceptionAsync(processingCommand, commandHandler, exception, currentRetryTimes), result => { var existingEventStream = result.Data; if (existingEventStream != null) { //这里,我们需要再重新做一遍更新内存缓存以及发布事件这两个操作; //之所以要这样做是因为虽然该command产生的事件已经持久化成功,但并不表示已经内存也更新了或者事件已经发布出去了; //因为有可能事件持久化成功了,但那时正好机器断电了,则更新内存和发布事件都没有做; _memoryCache.RefreshAggregateFromEventStore(existingEventStream.AggregateRootTypeName, existingEventStream.AggregateRootId); _eventService.PublishDomainEventAsync(processingCommand, existingEventStream); } else { //到这里,说明当前command执行遇到异常,然后当前command之前也没执行过,是第一次被执行。 //那就判断当前异常是否是需要被发布出去的异常,如果是,则发布该异常给所有消费者;否则,就记录错误日志; //然后,认为该command处理失败即可; var publishableException = exception as IPublishableException; if (publishableException != null) { PublishExceptionAsync(processingCommand, publishableException, 0); } else { LogCommandExecuteException(processingCommand, commandHandler, exception); NotifyCommandExecuted(processingCommand, CommandStatus.Failed, exception.GetType().Name, exception.Message); } } }, () => string.Format("[commandId:{0}]", command.Id), errorMessage => NotifyCommandExecuted(processingCommand, CommandStatus.Failed, typeof(string).FullName, errorMessage ?? "Get command async failed."), retryTimes); }
private void TryToRetryCommandForExceptionAsync(ProcessingCommand processingCommand, HandledCommand existingHandledCommand, ICommandHandlerProxy commandHandler, Exception exception, int retryTimes) { var command = processingCommand.Message; //到这里,说明当前command执行遇到异常,然后该command在commandStore中存在, //但是在eventStore中不存在,此时可以理解为该command还未被成功执行,此时做如下操作: //1.将command从commandStore中移除 //2.根据eventStore里的事件刷新缓存,目的是为了还原聚合根到最新状态,因为该聚合根的状态有可能已经被污染 //3.重试该command _ioHelper.TryAsyncActionRecursively <AsyncTaskResult>("RemoveCommandAsync", () => _commandStore.RemoveAsync(command.Id), currentRetryTimes => TryToRetryCommandForExceptionAsync(processingCommand, existingHandledCommand, commandHandler, exception, currentRetryTimes), result => { _memoryCache.RefreshAggregateFromEventStore(existingHandledCommand.AggregateRootTypeCode, existingHandledCommand.AggregateRootId); RetryCommand(processingCommand); }, () => string.Format("[commandId:{0}]", command.Id), () => NotifyCommandExecuted(processingCommand, CommandStatus.Failed, null, "Remove command async failed."), retryTimes); }
private void HandleExistingHandledCommandForExceptionAsync(ProcessingCommand processingCommand, HandledCommand existingHandledCommand, ICommandHandlerProxy commandHandler, Exception exception, int retryTimes) { var command = processingCommand.Message; var aggregateRootId = existingHandledCommand.AggregateRootId; _ioHelper.TryAsyncActionRecursively <AsyncTaskResult <DomainEventStream> >("FindEventStreamByCommandIdAsync", () => _eventStore.FindAsync(aggregateRootId, command.Id), currentRetryTimes => HandleExistingHandledCommandForExceptionAsync(processingCommand, existingHandledCommand, commandHandler, exception, currentRetryTimes), result => { var existingEventStream = result.Data; if (existingEventStream != null) { _eventService.PublishDomainEventAsync(processingCommand, existingEventStream); } else { LogCommandExecuteException(processingCommand, commandHandler, exception); TryToRetryCommandForExceptionAsync(processingCommand, existingHandledCommand, commandHandler, exception, 0); } }, () => string.Format("[aggregateRootId:{0}, commandId:{1}]", aggregateRootId, command.Id), () => NotifyCommandExecuted(processingCommand, CommandStatus.Failed, null, "Find event stream by command id async failed."), retryTimes); }