private void CommitEventAsync(EventCommittingContext context, int retryTimes) { _ioHelper.TryAsyncActionRecursively <AsyncTaskResult <EventAppendResult> >("PersistEventAsync", () => _eventStore.AppendAsync(context.EventStream), currentRetryTimes => CommitEventAsync(context, currentRetryTimes), result => { if (result.Data == EventAppendResult.Success) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Persist events success, {0}", context.EventStream); } RefreshAggregateMemoryCache(context); PublishDomainEventAsync(context.ProcessingCommand, context.EventStream); } else if (result.Data == EventAppendResult.DuplicateEvent) { HandleDuplicateEventResult(context); } else if (result.Data == EventAppendResult.DuplicateCommand) { HandleDuplicateCommandResult(context, 0); } }, () => string.Format("[eventStream:{0}]", context.EventStream), errorMessage => context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, context.EventStream.AggregateRootId, errorMessage ?? "Persist event async failed.", typeof(string).FullName)), retryTimes); }
private void HandleDuplicateCommandResult(EventCommittingContext context, int retryTimes) { var command = context.ProcessingCommand.Message; _ioHelper.TryAsyncActionRecursively <AsyncTaskResult <DomainEventStream> >("FindEventStreamByCommandIdAsync", () => _eventStore.FindAsync(command.AggregateRootId, command.Id), currentRetryTimes => HandleDuplicateCommandResult(context, currentRetryTimes), result => { var existingEventStream = result.Data; if (existingEventStream != null) { //这里,我们需要再重新做一遍更新内存缓存以及发布事件这两个操作; //之所以要这样做是因为虽然该command产生的事件已经持久化成功,但并不表示已经内存也更新了或者事件已经发布出去了; //因为有可能事件持久化成功了,但那时正好机器断电了,则更新内存和发布事件都没有做; RefreshAggregateMemoryCache(existingEventStream); PublishDomainEventAsync(context.ProcessingCommand, existingEventStream); } else { //到这里,说明当前command想添加到eventStore中时,提示command重复,但是尝试从eventStore中取出该command时却找不到该command。 //出现这种情况,我们就无法再做后续处理了,这种错误理论上不会出现,除非eventStore的Add接口和Get接口出现读写不一致的情况; //我们记录错误日志,然后认为当前command已被处理为失败。 var errorMessage = string.Format("Command exist in the event store, but we cannot get it from the event store. commandType:{0}, commandId:{1}, aggregateRootId:{2}", command.GetType().Name, command.Id, command.AggregateRootId); _logger.Error(errorMessage); context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, command.Id, command.AggregateRootId, "Duplicate command execution.", typeof(string).FullName)); } }, () => string.Format("[aggregateRootId:{0}, commandId:{1}]", command.AggregateRootId, command.Id), errorMessage => context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, command.Id, command.AggregateRootId, "Find event stream by commandId failed.", typeof(string).FullName)), retryTimes); }
public void CommitDomainEventAsync(EventCommittingContext context) { var eventMailbox = _eventMailboxDict.GetOrAdd(context.AggregateRoot.UniqueId, x => { return(new EventMailBox(x, _batchSize, committingContexts => { if (committingContexts == null || committingContexts.Count == 0) { return; } if (_eventStore.SupportBatchAppendEvent) { BatchPersistEventAsync(committingContexts, 0); } else { PersistEventOneByOne(committingContexts); } })); }); eventMailbox.EnqueueMessage(context); RefreshAggregateMemoryCache(context); context.ProcessingCommand.Mailbox.TryExecuteNextMessage(); }
private async Task ResetCommandMailBoxConsumingSequence(EventCommittingContext context, long consumingSequence) { var processingCommand = context.ProcessingCommand; var command = processingCommand.Message; var commandMailBox = processingCommand.MailBox; var eventMailBox = context.MailBox; var aggregateRootId = context.EventStream.AggregateRootId; commandMailBox.Pause(); try { eventMailBox.RemoveAggregateAllEventCommittingContexts(aggregateRootId); var refreshedAggregateRoot = await _memoryCache.RefreshAggregateFromEventStoreAsync(context.EventStream.AggregateRootTypeName, aggregateRootId); commandMailBox.ResetConsumingSequence(consumingSequence); } catch (Exception ex) { _logger.Error(string.Format("ResetCommandMailBoxConsumingSequence has unknown exception, aggregateRootId: {0}", command.AggregateRootId), ex); } finally { commandMailBox.Resume(); commandMailBox.TryRun(); eventMailBox.CompleteRun(); } }
private async Task ResetCommandMailBoxConsumingSequence(EventCommittingContext context, long consumingSequence) { var eventMailBox = context.MailBox; var processingCommand = context.ProcessingCommand; var command = processingCommand.Message; var commandMailBox = processingCommand.MailBox; commandMailBox.Pause(); try { await RefreshAggregateMemoryCacheToLatestVersion(context.EventStream.AggregateRootTypeName, context.EventStream.AggregateRootId); commandMailBox.ResetConsumingSequence(consumingSequence); eventMailBox.Clear(); eventMailBox.Exit(); _logger.InfoFormat("ResetCommandMailBoxConsumingSequence success, commandId: {0}, aggregateRootId: {1}, consumingSequence: {2}", command.Id, command.AggregateRootId, consumingSequence); } catch (Exception ex) { _logger.Error(string.Format("ResetCommandMailBoxConsumingOffset has unknown exception, commandId: {0}, aggregateRootId: {1}", command.Id, command.AggregateRootId), ex); } finally { commandMailBox.Resume(); } }
private void TryToRepublishEventAsync(EventCommittingContext context, int retryTimes) { var command = context.ProcessingCommand.Message; _ioHelper.TryAsyncActionRecursively("FindEventByCommandIdAsync", () => _eventStore.FindAsync(command.AggregateRootId, command.Id), currentRetryTimes => TryToRepublishEventAsync(context, currentRetryTimes), result => { var existingEventStream = result.Data; if (existingEventStream != null) { //这里,我们需要再重新做一遍发布事件这个操作; //之所以要这样做是因为虽然该command产生的事件已经持久化成功,但并不表示事件已经发布出去了; //因为有可能事件持久化成功了,但那时正好机器断电了,则发布事件都没有做; PublishDomainEventAsync(context.ProcessingCommand, existingEventStream); } else { //到这里,说明当前command想添加到eventStore中时,提示command重复,但是尝试从eventStore中取出该command时却找不到该command。 //出现这种情况,我们就无法再做后续处理了,这种错误理论上不会出现,除非eventStore的Add接口和Get接口出现读写不一致的情况; //框架会记录错误日志,让开发者排查具体是什么问题。 var errorMessage = string.Format("Command should be exist in the event store, but we cannot find it from the event store, this should not be happen, and we cannot continue again. commandType:{0}, commandId:{1}, aggregateRootId:{2}", command.GetType().Name, command.Id, command.AggregateRootId); _logger.Fatal(errorMessage); var commandResult = new CommandResult(CommandStatus.Failed, command.Id, command.AggregateRootId, "Command should be exist in the event store, but we cannot find it from the event store.", typeof(string).FullName); CompleteCommand(context.ProcessingCommand, commandResult); } }, () => string.Format("[aggregateRootId:{0}, commandId:{1}]", command.AggregateRootId, command.Id), null, retryTimes, true); }
private async Task ResetCommandMailBoxConsumingSequence(EventCommittingContext context, long consumingSequence, IList <string> duplicateCommandIdList) { var commandMailBox = context.ProcessingCommand.MailBox; var eventMailBox = context.MailBox; var aggregateRootId = context.EventStream.AggregateRootId; commandMailBox.Pause(); try { eventMailBox.RemoveAggregateAllEventCommittingContexts(aggregateRootId); var refreshedAggregateRoot = await _memoryCache.RefreshAggregateFromEventStoreAsync(context.EventStream.AggregateRootTypeName, aggregateRootId).ConfigureAwait(false); if (duplicateCommandIdList != null) { foreach (var commandId in duplicateCommandIdList) { commandMailBox.AddDuplicateCommandId(commandId); } } commandMailBox.ResetConsumingSequence(consumingSequence); } catch (Exception ex) { _logger.Error(string.Format("ResetCommandMailBoxConsumingSequence has unknown exception, aggregateRootId: {0}", aggregateRootId), ex); } finally { commandMailBox.Resume(); commandMailBox.TryRun(); } }
public void CommitDomainEventAsync(EventCommittingContext eventCommittingContext) { var eventMailboxIndex = GetEventMailBoxIndex(eventCommittingContext.EventStream.AggregateRootId); var eventMailbox = _eventCommittingContextMailBoxList[eventMailboxIndex]; eventMailbox.EnqueueMessage(eventCommittingContext); }
private void HandleFirstEventDuplicationAsync(EventCommittingContext context, int retryTimes) { var eventStream = context.EventStream; _ioHelper.TryAsyncActionRecursively("FindFirstEventByVersion", () => _eventStore.FindAsync(eventStream.AggregateRootId, 1), currentRetryTimes => HandleFirstEventDuplicationAsync(context, currentRetryTimes), result => { var firstEventStream = result.Data; if (firstEventStream != null) { //判断是否是同一个command,如果是,则再重新做一遍发布事件; //之所以要这样做,是因为虽然该command产生的事件已经持久化成功,但并不表示事件也已经发布出去了; //有可能事件持久化成功了,但那时正好机器断电了,则发布事件都没有做; if (context.ProcessingCommand.Message.Id == firstEventStream.CommandId) { ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence + 1).ContinueWith(t => { PublishDomainEventAsync(context.ProcessingCommand, firstEventStream); }).ConfigureAwait(false); } else { //如果不是同一个command,则认为是两个不同的command重复创建ID相同的聚合根,我们需要记录错误日志,然后通知当前command的处理完成; var errorMessage = string.Format("Duplicate aggregate creation. current commandId:{0}, existing commandId:{1}, aggregateRootId:{2}, aggregateRootTypeName:{3}", context.ProcessingCommand.Message.Id, firstEventStream.CommandId, firstEventStream.AggregateRootId, firstEventStream.AggregateRootTypeName); _logger.Error(errorMessage); ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence + 1).ContinueWith(t => { var commandResult = new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, "Duplicate aggregate creation.", typeof(string).FullName); CompleteCommand(context.ProcessingCommand, commandResult); }).ConfigureAwait(false); } } else { var errorMessage = string.Format("Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore, this should not be happen, and we cannot continue again. commandId:{0}, aggregateRootId:{1}, aggregateRootTypeName:{2}", eventStream.CommandId, eventStream.AggregateRootId, eventStream.AggregateRootTypeName); _logger.Fatal(errorMessage); ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence + 1).ContinueWith(t => { var commandResult = new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, "Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore.", typeof(string).FullName); CompleteCommand(context.ProcessingCommand, commandResult); }).ConfigureAwait(false); } }, () => string.Format("[eventStream:{0}]", eventStream), errorMessage => { _logger.Fatal(string.Format("Find the first version of event has unknown exception, the code should not be run to here, errorMessage: {0}", errorMessage)); }, retryTimes, true); }
private void RetryConcurrentCommand(EventCommittingContext context) { var processingCommand = context.ProcessingCommand; var command = processingCommand.Message; processingCommand.IncreaseConcurrentRetriedCount(); processingCommand.CommandExecuteContext.Clear(); _logger.InfoFormat("Begin to retry command as it meets the concurrent conflict. commandType:{0}, commandId:{1}, aggregateRootId:{2}, retried count:{3}.", command.GetType().Name, command.Id, processingCommand.Message.AggregateRootId, processingCommand.ConcurrentRetriedCount); _processingCommandHandler.HandleAsync(processingCommand); }
private void PersistEventAsync(EventCommittingContext context, int retryTimes) { _ioHelper.TryAsyncActionRecursively("PersistEventAsync", () => _eventStore.AppendAsync(context.EventStream), currentRetryTimes => PersistEventAsync(context, currentRetryTimes), result => { if (result.Data == EventAppendResult.Success) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Persist event success, {0}", context.EventStream); } Task.Factory.StartNew(x => { var currentContext = x as EventCommittingContext; PublishDomainEventAsync(currentContext.ProcessingCommand, currentContext.EventStream); }, context); if (context.Next != null) { PersistEventAsync(context.Next, 0); } else { context.MailBox.TryRun(true); } } else if (result.Data == EventAppendResult.DuplicateEvent) { if (context.EventStream.Version == 1) { HandleFirstEventDuplicationAsync(context, 0); } else { _logger.WarnFormat("Persist event has concurrent version conflict, eventStream: {0}", context.EventStream); ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence).ContinueWith(t => { }).ConfigureAwait(false); } } else if (result.Data == EventAppendResult.DuplicateCommand) { _logger.WarnFormat("Persist event has duplicate command, eventStream: {0}", context.EventStream); ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence + 1).ContinueWith(t => { }).ConfigureAwait(false); TryToRepublishEventAsync(context, 0); } }, () => string.Format("[eventStream:{0}]", context.EventStream), errorMessage => { _logger.Fatal(string.Format("Persist event has unknown exception, the code should not be run to here, errorMessage: {0}", errorMessage)); }, retryTimes, true); }
private void ProcessDuplicateEvent(EventCommittingContext eventCommittingContext) { if (eventCommittingContext.EventStream.Version == 1) { HandleFirstEventDuplicationAsync(eventCommittingContext, 0); } else { ResetCommandMailBoxConsumingSequence(eventCommittingContext, eventCommittingContext.ProcessingCommand.Sequence).ContinueWith(t => { }).ConfigureAwait(false); } }
private Task HandleFirstEventDuplicationAsync(EventCommittingContext context, int retryTimes) { var taskCompletionSource = new TaskCompletionSource <bool>(); _ioHelper.TryAsyncActionRecursively("FindFirstEventByVersion", () => _eventStore.FindAsync(context.EventStream.AggregateRootId, 1), currentRetryTimes => HandleFirstEventDuplicationAsync(context, currentRetryTimes), async result => { if (result != null) { var eventStream = result; //判断是否是同一个command,如果是,则再重新做一遍发布事件; //之所以要这样做,是因为虽然该command产生的事件已经持久化成功,但并不表示事件也已经发布出去了; //有可能事件持久化成功了,但那时正好机器断电了,则发布事件都没有做; if (context.ProcessingCommand.Message.Id == eventStream.CommandId) { await ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence + 1, null).ConfigureAwait(false); PublishDomainEventAsync(context.ProcessingCommand, eventStream); } else { //如果不是同一个command,则认为是两个不同的command重复创建ID相同的聚合根,我们需要记录错误日志,然后通知当前command的处理完成; var errorMessage = string.Format("Duplicate aggregate creation. current commandId:{0}, existing commandId:{1}, aggregateRootId:{2}, aggregateRootTypeName:{3}", context.ProcessingCommand.Message.Id, eventStream.CommandId, eventStream.AggregateRootId, eventStream.AggregateRootTypeName); _logger.Error(errorMessage); await ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence + 1, null).ConfigureAwait(false); var commandResult = new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, context.EventStream.AggregateRootId, "Duplicate aggregate creation.", typeof(string).FullName); await CompleteCommand(context.ProcessingCommand, commandResult); } } else { var errorMessage = string.Format("Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore, this should not be happen, and we cannot continue again. commandId:{0}, aggregateRootId:{1}, aggregateRootTypeName:{2}", context.EventStream.CommandId, context.EventStream.AggregateRootId, context.EventStream.AggregateRootTypeName); _logger.Fatal(errorMessage); await ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence + 1, null).ConfigureAwait(false); var commandResult = new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, context.EventStream.AggregateRootId, "Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore.", typeof(string).FullName); await CompleteCommand(context.ProcessingCommand, commandResult); } taskCompletionSource.SetResult(true); }, () => string.Format("[eventStream:{0}]", context.EventStream), null, retryTimes, true); return(taskCompletionSource.Task); }
public void CommitDomainEventAsync(EventCommittingContext context) { if (_enableGroupCommit && _eventStore.SupportBatchAppend) { _toCommitContextQueue.Enqueue(context); } else { CommitEventAsync(context, 0); } }
private void TryProcessNextContext(EventCommittingContext currentContext) { if (currentContext.Next != null) { PersistEventAsync(currentContext.Next, 0); } else { currentContext.EventMailBox.RegisterForExecution(true); } }
private void RefreshAggregateMemoryCache(EventCommittingContext context) { try { context.AggregateRoot.AcceptChanges(context.EventStream.Version); _memoryCache.Set(context.AggregateRoot); } catch (Exception ex) { _logger.Error(string.Format("Refresh aggregate memory cache failed for event stream:{0}", context.EventStream), ex); } }
private void RefreshAggregateMemoryCache(EventCommittingContext context) { try { context.AggregateRoot.AcceptChanges(context.EventStream.Version); _memoryCache.Set(context.AggregateRoot); _logger.DebugFormat("Refreshed aggregate memory cache, commandId:{0}, aggregateRootType:{1}, aggregateRootId:{2}, aggregateRootVersion:{3}", context.EventStream.CommandId, context.AggregateRoot.GetType().Name, context.AggregateRoot.UniqueId, context.AggregateRoot.Version); } catch (Exception ex) { _logger.Error(string.Format("Refresh memory cache failed by event stream:{0}", context.EventStream), ex); } }
private void ResetCommandMailBoxConsumingOffset(EventCommittingContext context, long consumeOffset) { var eventMailBox = context.EventMailBox; var processingCommand = context.ProcessingCommand; var commandMailBox = processingCommand.Mailbox; commandMailBox.StopHandlingMessage(); UpdateAggregateMemoryCacheToLatestVersion(context.EventStream); commandMailBox.ResetConsumingOffset(consumeOffset); eventMailBox.Clear(); eventMailBox.ExitHandlingMessage(); commandMailBox.RestartHandlingMessage(); }
private void PersistEventAsync(EventCommittingContext context, int retryTimes) { _ioHelper.TryAsyncActionRecursively("PersistEventAsync", () => _eventStore.AppendAsync(context.EventStream), currentRetryTimes => PersistEventAsync(context, currentRetryTimes), result => { if (result.Data == EventAppendResult.Success) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Persist event success, {0}", context.EventStream); } Task.Factory.StartNew(x => { var currentContext = x as EventCommittingContext; PublishDomainEventAsync(currentContext.ProcessingCommand, currentContext.EventStream); }, context); TryProcessNextContext(context); } else if (result.Data == EventAppendResult.DuplicateEvent) { //如果是当前事件的版本号为1,则认为是在创建重复的聚合根 if (context.EventStream.Version == 1) { HandleFirstEventDuplicationAsync(context, 0); } //如果事件的版本大于1,则认为是更新聚合根时遇到并发冲突了,则需要进行重试; else { _logger.WarnFormat("Persist event has concurrent version conflict, eventStream: {0}", context.EventStream); ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence); } } else if (result.Data == EventAppendResult.DuplicateCommand) { _logger.WarnFormat("Persist event has duplicate command, eventStream: {0}", context.EventStream); ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence + 1); TryToRepublishEventAsync(context, 0); context.EventMailBox.RegisterForExecution(true); } }, () => string.Format("[eventStream:{0}]", context.EventStream), errorMessage => { _logger.Fatal(string.Format("Persist event has unknown exception, the code should not be run to here, errorMessage: {0}", errorMessage)); }, retryTimes, true); }
private void HandleDuplicateEventResult(EventCommittingContext context) { //如果是当前事件的版本号为1,则认为是在创建重复的聚合根 if (context.EventStream.Version == 1) { HandleFirstEventDuplicationAsync(context, 0); } //如果事件的版本大于1,则认为是更新聚合根时遇到并发冲突了; //那么我们需要先将聚合根的最新状态更新到内存,然后重试command; else { UpdateAggregateToLatestVersion(context.EventStream.AggregateRootTypeCode, context.EventStream.AggregateRootId); RetryConcurrentCommand(context); } }
private void HandleFirstEventDuplicationAsync(EventCommittingContext context, int retryTimes) { var eventStream = context.EventStream; _ioHelper.TryAsyncActionRecursively <AsyncTaskResult <DomainEventStream> >("FindFirstEventByVersion", () => _eventStore.FindAsync(eventStream.AggregateRootId, 1), currentRetryTimes => HandleFirstEventDuplicationAsync(context, currentRetryTimes), result => { var firstEventStream = result.Data; if (firstEventStream != null) { //判断是否是同一个command,如果是,则再重新做一遍更新内存缓存以及发布事件这两个操作; //之所以要这样做,是因为虽然该command产生的事件已经持久化成功,但并不表示已经内存也更新了或者事件已经发布出去了; //有可能事件持久化成功了,但那时正好机器断电了,则更新内存和发布事件都没有做; if (context.ProcessingCommand.Message.Id == firstEventStream.CommandId) { RefreshAggregateMemoryCache(firstEventStream); PublishDomainEventAsync(context.ProcessingCommand, firstEventStream); } else { //如果不是同一个command,则认为是两个不同的command重复创建ID相同的聚合根,我们需要记录错误日志,然后通知当前command的处理完成; var errorMessage = string.Format("Duplicate aggregate creation. current commandId:{0}, existing commandId:{1}, aggregateRootId:{2}, aggregateRootTypeCode:{3}", context.ProcessingCommand.Message.Id, eventStream.CommandId, eventStream.AggregateRootId, eventStream.AggregateRootTypeCode); _logger.Error(errorMessage); context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, null, "Duplicate aggregate creation.")); } } else { var errorMessage = string.Format("Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore. commandId:{0}, aggregateRootId:{1}, aggregateRootTypeCode:{2}", eventStream.CommandId, eventStream.AggregateRootId, eventStream.AggregateRootTypeCode); _logger.Error(errorMessage); context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, null, "Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore.")); } }, () => string.Format("[eventStream:{0}]", eventStream), () => context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, null, "Persist the first version of event duplicated, but try to get the first version of domain event async failed.")), retryTimes); }
public void Run() { _lastActiveTime = DateTime.Now; IList <EventCommittingContext> contextList = null; try { EventCommittingContext context = null; while (_messageQueue.TryDequeue(out context)) { context.EventMailBox = this; if (contextList == null) { contextList = new List <EventCommittingContext>(); } contextList.Add(context); if (contextList.Count == _batchSize) { break; } } if (contextList != null && contextList.Count > 0) { _handleMessageAction(contextList); } } catch (Exception ex) { _logger.Error(string.Format("Event mailbox run has unknown exception, aggregateRootId: {0}", AggregateRootId), ex); Thread.Sleep(1); } finally { if (contextList == null || contextList.Count == 0) { Exit(); if (!_messageQueue.IsEmpty) { TryRun(); } } } }
public void Run() { IList <EventCommittingContext> contextList = null; try { EventCommittingContext context = null; while (_messageQueue.TryDequeue(out context)) { context.EventMailBox = this; if (contextList == null) { contextList = new List <EventCommittingContext>(); } contextList.Add(context); if (contextList.Count == _batchSize) { break; } } if (contextList != null && contextList.Count > 0) { _handleMessageAction(contextList); } } finally { if (contextList == null || contextList.Count == 0) { ExitHandlingMessage(); if (!_messageQueue.IsEmpty) { RegisterForExecution(); } } } }
private void ResetCommandMailBoxConsumingSequence(EventCommittingContext context, long consumingSequence) { var eventMailBox = context.EventMailBox; var processingCommand = context.ProcessingCommand; var commandMailBox = processingCommand.Mailbox; commandMailBox.PauseHandlingMessage(); try { UpdateAggregateMemoryCacheToLatestVersion(context.EventStream); commandMailBox.ResetConsumingSequence(consumingSequence); eventMailBox.Clear(); eventMailBox.ExitHandlingMessage(); } catch (Exception ex) { _logger.Error(string.Format("ResetCommandMailBoxConsumingOffset has unknown exception, commandId: {0}, aggregateRootId: {1}", processingCommand.Message.Id, processingCommand.Message.AggregateRootId), ex); } finally { commandMailBox.ResumeHandlingMessage(); } }
public void CommitDomainEventAsync(EventCommittingContext context) { var eventMailbox = _eventMailboxDict.GetOrAdd(context.AggregateRoot.UniqueId, x => { return new EventMailBox(x, _batchSize, committingContexts => { if (committingContexts == null || committingContexts.Count == 0) { return; } if (_eventStore.SupportBatchAppendEvent) { BatchPersistEventAsync(committingContexts, 0); } else { PersistEventOneByOne(committingContexts); } }); }); eventMailbox.EnqueueMessage(context); RefreshAggregateMemoryCache(context); context.ProcessingCommand.Mailbox.TryExecuteNextMessage(); }
private void HandleDuplicateEventResult(EventCommittingContext context) { //如果是当前事件的版本号为1,则认为是在创建重复的聚合根 if (context.EventStream.Version == 1) { HandleFirstEventDuplicationAsync(context, 0); } //如果事件的版本大于1,则认为是更新聚合根时遇到并发冲突了; //那么我们需要先将聚合根的最新状态更新到内存,然后重试command; else { UpdateAggregateToLatestVersion(context.EventStream.AggregateRootTypeName, context.EventStream.AggregateRootId); RetryConcurrentCommand(context); } }
private void TryProcessNextContext(EventCommittingContext currentContext) { if (currentContext.Next != null) { PersistEventAsync(currentContext.Next, 0); } else { currentContext.EventMailBox.RegisterForExecution(true); } }
public void EnqueueMessage(EventCommittingContext message) { _messageQueue.Enqueue(message); RegisterForExecution(); }
public void EnqueueMessage(EventCommittingContext message) { _messageQueue.Enqueue(message); RegisterForExecution(); }
public void CommitDomainEventAsync(EventCommittingContext context) { CommitEventAsync(context, 0); }
private void PersistEventAsync(EventCommittingContext context, int retryTimes) { _ioHelper.TryAsyncActionRecursively("PersistEventAsync", () => _eventStore.AppendAsync(context.EventStream), currentRetryTimes => PersistEventAsync(context, currentRetryTimes), result => { if (result.Data == EventAppendResult.Success) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Persist event success, {0}", context.EventStream); } Task.Factory.StartNew(x => { var currentContext = x as EventCommittingContext; PublishDomainEventAsync(currentContext.ProcessingCommand, currentContext.EventStream); }, context); TryProcessNextContext(context); } else if (result.Data == EventAppendResult.DuplicateEvent) { //如果是当前事件的版本号为1,则认为是在创建重复的聚合根 if (context.EventStream.Version == 1) { HandleFirstEventDuplicationAsync(context, 0); } //如果事件的版本大于1,则认为是更新聚合根时遇到并发冲突了,则需要进行重试; else { _logger.WarnFormat("Persist event has concurrent version conflict, eventStream: {0}", context.EventStream); ResetCommandMailBoxConsumingOffset(context, context.ProcessingCommand.Sequence); } } else if (result.Data == EventAppendResult.DuplicateCommand) { _logger.WarnFormat("Persist event has duplicate command, eventStream: {0}", context.EventStream); ResetCommandMailBoxConsumingOffset(context, context.ProcessingCommand.Sequence + 1); TryToRepublishEventAsync(context, 0); context.EventMailBox.RegisterForExecution(true); } }, () => string.Format("[eventStream:{0}]", context.EventStream), errorMessage => { _logger.Fatal(string.Format("Persist event has unknown exception, the code should not be run to here, errorMessage: {0}", errorMessage)); }, retryTimes, true); }
private void RefreshAggregateMemoryCache(EventCommittingContext context) { try { context.AggregateRoot.AcceptChanges(context.EventStream.Version); _memoryCache.Set(context.AggregateRoot); } catch (Exception ex) { _logger.Error(string.Format("Refresh memory cache failed for event stream:{0}", context.EventStream), ex); } }
private void ResetCommandMailBoxConsumingOffset(EventCommittingContext context, long consumeOffset) { var eventMailBox = context.EventMailBox; var processingCommand = context.ProcessingCommand; var commandMailBox = processingCommand.Mailbox; commandMailBox.StopHandlingMessage(); UpdateAggregateMemoryCacheToLatestVersion(context.EventStream); commandMailBox.ResetConsumingOffset(consumeOffset); eventMailBox.Clear(); eventMailBox.ExitHandlingMessage(); commandMailBox.RestartHandlingMessage(); }
private void CommitEventAsync(EventCommittingContext context, int retryTimes) { _ioHelper.TryAsyncActionRecursively<AsyncTaskResult<EventAppendResult>>("PersistEventAsync", () => _eventStore.AppendAsync(context.EventStream), currentRetryTimes => CommitEventAsync(context, currentRetryTimes), result => { if (result.Data == EventAppendResult.Success) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Persist events success, {0}", context.EventStream); } RefreshAggregateMemoryCache(context); PublishDomainEventAsync(context.ProcessingCommand, context.EventStream); } else if (result.Data == EventAppendResult.DuplicateEvent) { HandleDuplicateEventResult(context); } else if (result.Data == EventAppendResult.DuplicateCommand) { HandleDuplicateCommandResult(context, 0); } }, () => string.Format("[eventStream:{0}]", context.EventStream), errorMessage => context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, context.EventStream.AggregateRootId, errorMessage ?? "Persist event async failed.", typeof(string).FullName)), retryTimes); }
private void HandleFirstEventDuplicationAsync(EventCommittingContext context, int retryTimes) { var eventStream = context.EventStream; _ioHelper.TryAsyncActionRecursively("FindFirstEventByVersion", () => _eventStore.FindAsync(eventStream.AggregateRootId, 1), currentRetryTimes => HandleFirstEventDuplicationAsync(context, currentRetryTimes), result => { var firstEventStream = result.Data; if (firstEventStream != null) { //判断是否是同一个command,如果是,则再重新做一遍发布事件; //之所以要这样做,是因为虽然该command产生的事件已经持久化成功,但并不表示事件也已经发布出去了; //有可能事件持久化成功了,但那时正好机器断电了,则发布事件都没有做; if (context.ProcessingCommand.Message.Id == firstEventStream.CommandId) { ResetCommandMailBoxConsumingOffset(context, context.ProcessingCommand.Sequence + 1); PublishDomainEventAsync(context.ProcessingCommand, firstEventStream); } else { //如果不是同一个command,则认为是两个不同的command重复创建ID相同的聚合根,我们需要记录错误日志,然后通知当前command的处理完成; var errorMessage = string.Format("Duplicate aggregate creation. current commandId:{0}, existing commandId:{1}, aggregateRootId:{2}, aggregateRootTypeName:{3}", context.ProcessingCommand.Message.Id, firstEventStream.CommandId, firstEventStream.AggregateRootId, firstEventStream.AggregateRootTypeName); _logger.Error(errorMessage); ResetCommandMailBoxConsumingOffset(context, context.ProcessingCommand.Sequence + 1); CompleteCommand(context.ProcessingCommand, new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, "Duplicate aggregate creation.", typeof(string).FullName)); } } else { var errorMessage = string.Format("Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore, this should not be happen, and we cannot continue again. commandId:{0}, aggregateRootId:{1}, aggregateRootTypeName:{2}", eventStream.CommandId, eventStream.AggregateRootId, eventStream.AggregateRootTypeName); _logger.Fatal(errorMessage); } }, () => string.Format("[eventStream:{0}]", eventStream), errorMessage => { _logger.Fatal(string.Format("Find the first version of event has unknown exception, the code should not be run to here, errorMessage: {0}", errorMessage)); }, retryTimes, true); }
private void HandleDuplicateCommandResult(EventCommittingContext context, int retryTimes) { var command = context.ProcessingCommand.Message; _ioHelper.TryAsyncActionRecursively<AsyncTaskResult<DomainEventStream>>("FindEventStreamByCommandIdAsync", () => _eventStore.FindAsync(command.AggregateRootId, command.Id), currentRetryTimes => HandleDuplicateCommandResult(context, currentRetryTimes), result => { var existingEventStream = result.Data; if (existingEventStream != null) { //这里,我们需要再重新做一遍更新内存缓存以及发布事件这两个操作; //之所以要这样做是因为虽然该command产生的事件已经持久化成功,但并不表示已经内存也更新了或者事件已经发布出去了; //因为有可能事件持久化成功了,但那时正好机器断电了,则更新内存和发布事件都没有做; RefreshAggregateMemoryCache(existingEventStream); PublishDomainEventAsync(context.ProcessingCommand, existingEventStream); } else { //到这里,说明当前command想添加到eventStore中时,提示command重复,但是尝试从eventStore中取出该command时却找不到该command。 //出现这种情况,我们就无法再做后续处理了,这种错误理论上不会出现,除非eventStore的Add接口和Get接口出现读写不一致的情况; //我们记录错误日志,然后认为当前command已被处理为失败。 var errorMessage = string.Format("Command exist in the event store, but we cannot get it from the event store. commandType:{0}, commandId:{1}, aggregateRootId:{2}", command.GetType().Name, command.Id, command.AggregateRootId); _logger.Error(errorMessage); context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, command.Id, command.AggregateRootId, "Duplicate command execution.", typeof(string).FullName)); } }, () => string.Format("[aggregateRootId:{0}, commandId:{1}]", command.AggregateRootId, command.Id), errorMessage => context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, command.Id, command.AggregateRootId, "Find event stream by commandId failed.", typeof(string).FullName)), retryTimes); }
public void EnqueueMessage(EventCommittingContext message) { _messageQueue.Enqueue(message); _lastActiveTime = DateTime.Now; TryRun(); }
private void TryToRepublishEventAsync(EventCommittingContext context, int retryTimes) { var command = context.ProcessingCommand.Message; _ioHelper.TryAsyncActionRecursively("FindEventByCommandIdAsync", () => _eventStore.FindAsync(command.AggregateRootId, command.Id), currentRetryTimes => TryToRepublishEventAsync(context, currentRetryTimes), result => { var existingEventStream = result.Data; if (existingEventStream != null) { //这里,我们需要再重新做一遍发布事件这个操作; //之所以要这样做是因为虽然该command产生的事件已经持久化成功,但并不表示事件已经发布出去了; //因为有可能事件持久化成功了,但那时正好机器断电了,则发布事件都没有做; PublishDomainEventAsync(context.ProcessingCommand, existingEventStream); } else { //到这里,说明当前command想添加到eventStore中时,提示command重复,但是尝试从eventStore中取出该command时却找不到该command。 //出现这种情况,我们就无法再做后续处理了,这种错误理论上不会出现,除非eventStore的Add接口和Get接口出现读写不一致的情况; //框架会记录错误日志,让开发者排查具体是什么问题。 var errorMessage = string.Format("Command exist in the event store, but we cannot find it from the event store, this should not be happen, and we cannot continue again. commandType:{0}, commandId:{1}, aggregateRootId:{2}", command.GetType().Name, command.Id, command.AggregateRootId); _logger.Fatal(errorMessage); } }, () => string.Format("[aggregateRootId:{0}, commandId:{1}]", command.AggregateRootId, 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 void RefreshAggregateMemoryCache(EventCommittingContext context) { try { context.AggregateRoot.AcceptChanges(context.EventStream.Version); _memoryCache.Set(context.AggregateRoot); if (_logger.IsDebugEnabled) { _logger.DebugFormat("Refreshed aggregate memory cache, commandId:{0}, aggregateRootType:{1}, aggregateRootId:{2}, aggregateRootVersion:{3}", context.EventStream.CommandId, context.AggregateRoot.GetType().Name, context.AggregateRoot.UniqueId, context.AggregateRoot.Version); } } catch (Exception ex) { _logger.Error(string.Format("Refresh memory cache failed by event stream:{0}", context.EventStream), ex); } }
private void RetryConcurrentCommand(EventCommittingContext context) { var processingCommand = context.ProcessingCommand; var command = processingCommand.Message; processingCommand.IncreaseConcurrentRetriedCount(); processingCommand.CommandExecuteContext.Clear(); _logger.InfoFormat("Begin to retry command as it meets the concurrent conflict. commandType:{0}, commandId:{1}, aggregateRootId:{2}, retried count:{3}.", command.GetType().Name, command.Id, processingCommand.Message.AggregateRootId, processingCommand.ConcurrentRetriedCount); _processingCommandHandler.HandleAsync(processingCommand); }
public void CommitDomainEventAsync(EventCommittingContext context) { if (_enableGroupCommit && _eventStore.SupportBatchAppend) { _toCommitContextQueue.Enqueue(context); } else { CommitEventAsync(context, 0); } }
private void HandleFirstEventDuplicationAsync(EventCommittingContext context, int retryTimes) { var eventStream = context.EventStream; _ioHelper.TryAsyncActionRecursively<AsyncTaskResult<DomainEventStream>>("FindFirstEventByVersion", () => _eventStore.FindAsync(eventStream.AggregateRootId, 1), currentRetryTimes => HandleFirstEventDuplicationAsync(context, currentRetryTimes), result => { var firstEventStream = result.Data; if (firstEventStream != null) { //判断是否是同一个command,如果是,则再重新做一遍更新内存缓存以及发布事件这两个操作; //之所以要这样做,是因为虽然该command产生的事件已经持久化成功,但并不表示已经内存也更新了或者事件已经发布出去了; //有可能事件持久化成功了,但那时正好机器断电了,则更新内存和发布事件都没有做; if (context.ProcessingCommand.Message.Id == firstEventStream.CommandId) { RefreshAggregateMemoryCache(firstEventStream); PublishDomainEventAsync(context.ProcessingCommand, firstEventStream); } else { //如果不是同一个command,则认为是两个不同的command重复创建ID相同的聚合根,我们需要记录错误日志,然后通知当前command的处理完成; var errorMessage = string.Format("Duplicate aggregate creation. current commandId:{0}, existing commandId:{1}, aggregateRootId:{2}, aggregateRootTypeName:{3}", context.ProcessingCommand.Message.Id, eventStream.CommandId, eventStream.AggregateRootId, eventStream.AggregateRootTypeName); _logger.Error(errorMessage); context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, "Duplicate aggregate creation.", typeof(string).FullName)); } } else { var errorMessage = string.Format("Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore. commandId:{0}, aggregateRootId:{1}, aggregateRootTypeName:{2}", eventStream.CommandId, eventStream.AggregateRootId, eventStream.AggregateRootTypeName); _logger.Error(errorMessage); context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, "Duplicate aggregate creation, but we cannot find the existing eventstream from eventstore.", typeof(string).FullName)); } }, () => string.Format("[eventStream:{0}]", eventStream), errorMessage => context.ProcessingCommand.Complete(new CommandResult(CommandStatus.Failed, context.ProcessingCommand.Message.Id, eventStream.AggregateRootId, errorMessage ?? "Persist the first version of event duplicated, but try to get the first version of domain event async failed.", typeof(string).FullName)), retryTimes); }
public void CommitDomainEventAsync(EventCommittingContext context) { CommitEventAsync(context, 0); }