private void BatchPersistEventsAsync(IEnumerable <EventCommittingContext> contextList, int retryTimes) { _ioHelper.TryAsyncActionRecursively <AsyncTaskResult>("BatchPersistEventAsync", () => _eventStore.BatchAppendAsync(contextList.Select(x => x.EventStream)), currentRetryTimes => BatchPersistEventsAsync(contextList, currentRetryTimes), result => { _successPersistedContextQueue.Add(contextList); _logger.DebugFormat("Batch persist event stream success, persisted event stream count:{0}", contextList.Count()); if (_toCommitContextQueue.Count >= _groupCommitMaxSize) { BatchPersistEventsAsync(DequeueContexts(), 0); } else { ExitBatchPersistingEvents(); } }, () => string.Format("[contextListCount:{0}]", contextList.Count()), () => { _failedPersistedContextQueue.Add(contextList); ExitBatchPersistingEvents(); }, retryTimes); }
private void BatchPersistEventAsync(IList <EventCommittingContext> committingContexts, int retryTimes) { _ioHelper.TryAsyncActionRecursively("BatchPersistEventAsync", () => _eventStore.BatchAppendAsync(committingContexts.Select(x => x.EventStream)), currentRetryTimes => BatchPersistEventAsync(committingContexts, currentRetryTimes), result => { var eventMailBox = committingContexts.First().EventMailBox; var appendResult = result.Data; if (appendResult == EventAppendResult.Success) { if (_logger.IsDebugEnabled) { _logger.DebugFormat("Batch persist event success, aggregateRootId: {0}, eventStreamCount: {1}", eventMailBox.AggregateRootId, committingContexts.Count); } Task.Factory.StartNew(x => { var contextList = x as IList <EventCommittingContext>; foreach (var context in contextList) { PublishDomainEventAsync(context.ProcessingCommand, context.EventStream); } }, committingContexts); eventMailBox.RegisterForExecution(true); } else if (appendResult == EventAppendResult.DuplicateEvent) { var context = committingContexts.First(); if (context.EventStream.Version == 1) { ConcatConetxts(committingContexts); HandleFirstEventDuplicationAsync(context, 0); } else { _logger.WarnFormat("Batch persist event has concurrent version conflict, first eventStream: {0}, batchSize: {1}", context.EventStream, committingContexts.Count); ResetCommandMailBoxConsumingSequence(context, context.ProcessingCommand.Sequence); } } else if (appendResult == EventAppendResult.DuplicateCommand) { PersistEventOneByOne(committingContexts); } }, () => string.Format("[contextListCount:{0}]", committingContexts.Count), errorMessage => { _logger.Fatal(string.Format("Batch persist event has unknown exception, the code should not be run to here, errorMessage: {0}", errorMessage)); }, retryTimes, true); }
private void BatchPersistEventAsync(IList <EventCommittingContext> committingContexts, int retryTimes) { _ioHelper.TryAsyncActionRecursively("BatchPersistEventAsync", () => _eventStore.BatchAppendAsync(committingContexts.Select(x => x.EventStream)), currentRetryTimes => BatchPersistEventAsync(committingContexts, currentRetryTimes), result => { var appendResult = result.Data; if (appendResult == EventAppendResult.Success) { var eventMailBox = committingContexts.First().MailBox; _logger.InfoFormat("Batch persist event success, routingKey: {0}, eventStreamCount: {1}, minEventVersion: {2}, maxEventVersion: {3}", eventMailBox.RoutingKey, committingContexts.Count, committingContexts.First().EventStream.Version, committingContexts.Last().EventStream.Version); Task.Factory.StartNew(x => { var contextList = x as IList <EventCommittingContext>; foreach (var context in contextList) { PublishDomainEventAsync(context.ProcessingCommand, context.EventStream); } }, committingContexts); foreach (var committingContext in committingContexts) { committingContext.MailBox.CompleteMessage(committingContext, true); } eventMailBox.CompleteRun(); } else if (appendResult == EventAppendResult.DuplicateEvent) { var eventMailBox = committingContexts.First().MailBox; _logger.WarnFormat("Batch persist event has concurrent version conflict, routingKey: {0}, eventStreamCount: {1}, minEventVersion: {2}, maxEventVersion: {3}", eventMailBox.RoutingKey, committingContexts.Count, committingContexts.First().EventStream.Version, committingContexts.Last().EventStream.Version); ProcessDuplicateEvent(committingContexts.First()); } else if (appendResult == EventAppendResult.DuplicateCommand) { PersistEventOneByOne(committingContexts); } }, () => string.Format("[contextListCount:{0}]", committingContexts.Count), errorMessage => { _logger.Fatal(string.Format("Batch persist event has unknown exception, the code should not be run to here, errorMessage: {0}", errorMessage)); }, retryTimes, true); }
public async Task Should_Append_EventStream() { //Arrange var eventStream = GetTestDomainEventStream(ObjectId.GenerateNewStringId()); //Act await _store.BatchAppendAsync(new List <DomainEventStream> { eventStream }); //Assert var result = await _store.FindAsync(eventStream.AggregateRootId, eventStream.Version); result.AggregateRootId.ShouldBe(eventStream.AggregateRootId); result.AggregateRootTypeName.ShouldBe(eventStream.AggregateRootTypeName); result.Version.ShouldBe(eventStream.Version); foreach (var @event in result.Events) { eventStream.Events.ToList().Select(e => e.AggregateRootStringId).ShouldContain(@event.AggregateRootStringId); } result.CommandId.ShouldBe(eventStream.CommandId); result.ShouldNotBeNull(); }
private void BatchPersistEventAsync(IList <EventCommittingContext> committingContexts, int retryTimes) { _ioHelper.TryAsyncActionRecursively("BatchPersistEventAsync", () => _eventStore.BatchAppendAsync(committingContexts.Select(x => x.EventStream)), currentRetryTimes => BatchPersistEventAsync(committingContexts, currentRetryTimes), result => { var eventMailBox = committingContexts.First().MailBox; var appendResult = result.Data; //针对持久化成功的聚合根,发布这些聚合根的事件到Q端 if (appendResult.SuccessAggregateRootIdList != null && appendResult.SuccessAggregateRootIdList.Count > 0) { var successCommittedContextDict = new Dictionary <string, IList <EventCommittingContext> >(); foreach (var aggregateRootId in appendResult.SuccessAggregateRootIdList) { var contextList = committingContexts.Where(x => x.EventStream.AggregateRootId == aggregateRootId).ToList(); if (contextList.Count > 0) { successCommittedContextDict.Add(aggregateRootId, contextList); } } if (_logger.IsDebugEnabled) { _logger.DebugFormat("Batch persist events, mailboxNumber: {0}, succeedAggregateRootCount: {1}, eventStreamDetail: {2}", eventMailBox.Number, appendResult.SuccessAggregateRootIdList.Count, _jsonSerializer.Serialize(successCommittedContextDict)); } Task.Factory.StartNew(x => { var contextListDict = x as Dictionary <string, IList <EventCommittingContext> >; foreach (var entry in contextListDict) { foreach (var committingContext in entry.Value) { PublishDomainEventAsync(committingContext.ProcessingCommand, committingContext.EventStream); } } }, successCommittedContextDict); } //针对持久化出现重复的命令ID,则重新发布这些命令对应的领域事件到Q端 if (appendResult.DuplicateCommandIdList != null && appendResult.DuplicateCommandIdList.Count > 0) { _logger.WarnFormat("Batch persist events, mailboxNumber: {0}, duplicateCommandIdCount: {1}, detail: {2}", eventMailBox.Number, appendResult.DuplicateCommandIdList.Count, _jsonSerializer.Serialize(appendResult.DuplicateCommandIdList)); foreach (var commandId in appendResult.DuplicateCommandIdList) { var committingContext = committingContexts.FirstOrDefault(x => x.ProcessingCommand.Message.Id == commandId); if (committingContext != null) { TryToRepublishEventAsync(committingContext, 0); } } } //针对持久化出现版本冲突的聚合根,则自动处理每个聚合根的冲突 if (appendResult.DuplicateEventAggregateRootIdList != null && appendResult.DuplicateEventAggregateRootIdList.Count > 0) { _logger.WarnFormat("Batch persist events, mailboxNumber: {0}, duplicateEventAggregateRootCount: {1}, detail: {2}", eventMailBox.Number, appendResult.DuplicateEventAggregateRootIdList.Count, _jsonSerializer.Serialize(appendResult.DuplicateEventAggregateRootIdList)); foreach (var aggregateRootId in appendResult.DuplicateEventAggregateRootIdList) { var committingContext = committingContexts.FirstOrDefault(x => x.EventStream.AggregateRootId == aggregateRootId); if (committingContext != null) { ProcessAggregateDuplicateEvent(committingContext); } } } //最终,将当前的EventMailBox的本次处理标记为处理完成,然后继续可以处理下一批事件 eventMailBox.CompleteRun(); }, () => string.Format("[contextListCount:{0}]", committingContexts.Count), null, retryTimes, true); }
private void BatchPersistEventAsync(IList <EventCommittingContext> committingContexts, int retryTimes) { if (committingContexts == null || committingContexts.Count == 0) { return; } _ioHelper.TryAsyncActionRecursively("BatchPersistEventAsync", () => _eventStore.BatchAppendAsync(committingContexts.Select(x => x.EventStream)), currentRetryTimes => BatchPersistEventAsync(committingContexts, currentRetryTimes), async result => { var eventMailBox = committingContexts.First().MailBox; if (result == null) { _logger.FatalFormat("Batch persist events success, but the persist result is null, the current event committing mailbox should be pending, mailboxNumber: {0}", eventMailBox.Number); return; } //针对持久化成功的聚合根,正常发布这些聚合根的事件到Q端 if (result.SuccessAggregateRootIdList != null && result.SuccessAggregateRootIdList.Count > 0) { foreach (var aggregateRootId in result.SuccessAggregateRootIdList) { var committingContextList = committingContexts.Where(x => x.EventStream.AggregateRootId == aggregateRootId).ToList(); if (committingContextList.Count > 0) { foreach (var committingContext in committingContextList) { PublishDomainEventAsync(committingContext.ProcessingCommand, committingContext.EventStream); } if (_logger.IsDebugEnabled) { _logger.DebugFormat("Batch persist events success, mailboxNumber: {0}, aggregateRootId: {1}", eventMailBox.Number, aggregateRootId); } } } } //针对持久化出现重复的命令ID,在命令MailBox中标记为已重复,在事件MailBox中清除对应聚合根产生的事件,且重新发布这些命令对应的领域事件到Q端 if (result.DuplicateCommandAggregateRootIdList != null && result.DuplicateCommandAggregateRootIdList.Count > 0) { foreach (var entry in result.DuplicateCommandAggregateRootIdList) { var committingContext = committingContexts.FirstOrDefault(x => x.AggregateRoot.UniqueId == entry.Key); if (committingContext != null) { _logger.WarnFormat("Batch persist events has duplicate commandIds, mailboxNumber: {0}, aggregateRootId: {1}, commandIds: {2}", eventMailBox.Number, entry.Key, string.Join(",", entry.Value)); await ResetCommandMailBoxConsumingSequence(committingContext, committingContext.ProcessingCommand.Sequence, entry.Value).ConfigureAwait(false); TryToRepublishEventAsync(committingContext, 0); } } } //针对持久化出现版本冲突的聚合根,则自动处理每个聚合根的冲突 if (result.DuplicateEventAggregateRootIdList != null && result.DuplicateEventAggregateRootIdList.Count > 0) { foreach (var aggregateRootId in result.DuplicateEventAggregateRootIdList) { var committingContext = committingContexts.FirstOrDefault(x => x.EventStream.AggregateRootId == aggregateRootId); if (committingContext != null) { _logger.WarnFormat("Batch persist events has version confliction, mailboxNumber: {0}, aggregateRootId: {1}, conflictVersion: {2}", eventMailBox.Number, committingContext.EventStream.AggregateRootId, committingContext.EventStream.Version); if (committingContext.EventStream.Version == 1) { await HandleFirstEventDuplicationAsync(committingContext, 0); } else { await ResetCommandMailBoxConsumingSequence(committingContext, committingContext.ProcessingCommand.Sequence, null).ContinueWith(t => { }).ConfigureAwait(false); } } } } committingContexts.First().MailBox.CompleteRun(); }, () => string.Format("[contextListCount:{0}]", committingContexts.Count), null, retryTimes, true); }