protected void ConsumeMessage(BrokeredMessage brokeredMessage) { var eventContext = new MessageContext(brokeredMessage); var message = eventContext.Message; var messageHandlerTypes = _handlerProvider.GetHandlerTypes(message.GetType()); if (messageHandlerTypes.Count == 0) { return; } messageHandlerTypes.ForEach(messageHandlerType => { PerMessageContextLifetimeManager.CurrentMessageContext = eventContext; eventContext.ToBeSentMessageContexts.Clear(); var messageStore = IoCFactory.Resolve <IMessageStore>(); var subscriptionName = string.Format("{0}.{1}", _subscriptionName, messageHandlerType.FullName); if (!messageStore.HasEventHandled(eventContext.MessageID, subscriptionName)) { try { var messageHandler = IoCFactory.Resolve(messageHandlerType); ((dynamic)messageHandler).Handle((dynamic)message); var commandContexts = eventContext.ToBeSentMessageContexts; var eventBus = IoCFactory.Resolve <IEventBus>(); var messageContexts = new List <MessageContext>(); eventBus.GetMessages().ForEach(msg => messageContexts.Add(new MessageContext(msg))); messageStore.SaveEvent(eventContext, subscriptionName, commandContexts, messageContexts); if (commandContexts.Count > 0) { ((CommandBus)IoCFactory.Resolve <ICommandBus>()).SendCommands(commandContexts.AsEnumerable()); } if (messageContexts.Count > 0) { IoCFactory.Resolve <IEventPublisher>().Publish(messageContexts.ToArray()); } } catch (Exception e) { if (e is DomainException) { _logger.Warn(message.ToJson(), e); } else { //IO error or sytem Crash _logger.Error(message.ToJson(), e); } messageStore.SaveFailHandledEvent(eventContext, subscriptionName, e); } finally { PerMessageContextLifetimeManager.CurrentMessageContext = null; } } }); }
protected async Task ConsumeMessage(IMessageContext eventContext) { try { _logger?.Debug($"start handle event {_consumerId} {eventContext.Message.ToJson()}"); var message = eventContext.Message; var sagaInfo = eventContext.SagaInfo; var messageHandlerTypes = _handlerProvider.GetHandlerTypes(message.GetType()); if (messageHandlerTypes.Count == 0) { _logger?.Debug($"event has no handlerTypes, message:{message.ToJson()}"); _internalConsumer.CommitOffset(eventContext); return; } //messageHandlerTypes.ForEach(messageHandlerType => foreach (var messageHandlerType in messageHandlerTypes) { using (var scope = IoCFactory.Instance.CurrentContainer.CreateChildContainer()) { scope.RegisterInstance(typeof(IMessageContext), eventContext); var messageStore = scope.Resolve <IMessageStore>(); var subscriptionName = $"{_subscriptionName}.{messageHandlerType.Type.FullName}"; if (!messageStore.HasEventHandled(eventContext.MessageID, subscriptionName)) { var eventMessageStates = new List <MessageState>(); var commandMessageStates = new List <MessageState>(); var eventBus = scope.Resolve <IEventBus>(); try { var messageHandler = scope.Resolve(messageHandlerType.Type); using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) { if (messageHandlerType.IsAsync) { await((dynamic)messageHandler).Handle((dynamic)message) .ConfigureAwait(false); } else { await Task.Run(() => { ((dynamic)messageHandler).Handle((dynamic)message); }) .ConfigureAwait(false); } //get commands to be sent eventBus.GetCommands() .ForEach(cmd => commandMessageStates.Add(new MessageState(_commandBus?.WrapCommand(cmd, sagaInfo: sagaInfo, producer: Producer))) ); //get events to be published eventBus.GetEvents() .ForEach(msg => { var topic = msg.GetFormatTopic(); eventMessageStates.Add(new MessageState(_messageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo, producer: Producer))); }); eventBus.GetToPublishAnywayMessages() .ForEach(msg => { var topic = msg.GetFormatTopic(); eventMessageStates.Add(new MessageState(_messageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo, producer: Producer))); }); eventMessageStates.AddRange(GetSagaReplyMessageStates(sagaInfo, eventBus)); messageStore.HandleEvent(eventContext, subscriptionName, commandMessageStates.Select(s => s.MessageContext), eventMessageStates.Select(s => s.MessageContext)); transactionScope.Complete(); } if (commandMessageStates.Count > 0) { _commandBus?.SendMessageStates(commandMessageStates); } if (eventMessageStates.Count > 0) { _messagePublisher?.SendAsync(eventMessageStates.ToArray()); } } catch (Exception e) { eventMessageStates.Clear(); messageStore.Rollback(); if (e is DomainException) { var domainExceptionEvent = ((DomainException)e).DomainExceptionEvent; if (domainExceptionEvent != null) { var topic = domainExceptionEvent.GetFormatTopic(); var exceptionMessage = _messageQueueClient.WrapMessage(domainExceptionEvent, eventContext.MessageID, topic, producer: Producer); eventMessageStates.Add(new MessageState(exceptionMessage)); } _logger?.Warn(message.ToJson(), e); } else { //IO error or sytem Crash //if we meet with unknown exception, we interrupt saga if (sagaInfo != null) { eventBus.FinishSaga(e); } _logger?.Error(message.ToJson(), e); } eventBus.GetToPublishAnywayMessages() .ForEach(msg => { var topic = msg.GetFormatTopic(); eventMessageStates.Add(new MessageState(_messageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo, producer: Producer))); }); eventMessageStates.AddRange(GetSagaReplyMessageStates(sagaInfo, eventBus)); messageStore.SaveFailHandledEvent(eventContext, subscriptionName, e, eventMessageStates.Select(s => s.MessageContext).ToArray()); if (eventMessageStates.Count > 0) { _messagePublisher?.SendAsync(eventMessageStates.ToArray()); } } } } } } catch (Exception e) { _logger?.Fatal($"Handle event failed event: {eventContext.ToJson()}", e); } _internalConsumer.CommitOffset(eventContext); }
protected async virtual Task ConsumeMessage(IMessageContext commandContext) { var command = commandContext.Message as ICommand; var needReply = !string.IsNullOrEmpty(commandContext.ReplyToEndPoint); var sagaInfo = commandContext.SagaInfo; IMessageContext messageReply = null; if (command == null) { return; } var needRetry = command.NeedRetry; using (var scope = IoCFactory.Instance.CurrentContainer.CreateChildContainer()) { scope.RegisterInstance(typeof(IMessageContext), commandContext); var eventMessageStates = new List <MessageState>(); var messageStore = scope.Resolve <IMessageStore>(); var eventBus = scope.Resolve <IEventBus>(); var commandHasHandled = messageStore.HasCommandHandled(commandContext.MessageID); if (commandHasHandled) { if (needReply) { messageReply = _messageQueueClient.WrapMessage(new MessageDuplicatelyHandled(), commandContext.MessageID, commandContext.ReplyToEndPoint); eventMessageStates.Add(new MessageState(messageReply)); } } else { var messageHandlerType = _handlerProvider.GetHandlerTypes(command.GetType()).FirstOrDefault(); _logger.InfoFormat("Handle command, commandID:{0}", commandContext.MessageID); if (messageHandlerType == null) { if (needReply) { messageReply = _messageQueueClient.WrapMessage(new NoHandlerExists(), commandContext.MessageID, commandContext.ReplyToEndPoint); eventMessageStates.Add(new MessageState(messageReply)); } } else { object messageHandler = null; do { try { if (messageHandler == null) { messageHandler = scope.Resolve(messageHandlerType.Type); } using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }, TransactionScopeAsyncFlowOption.Enabled)) { if (messageHandlerType.IsAsync) { await((dynamic)messageHandler).Handle((dynamic)command) .ConfigureAwait(false); } else { await Task.Run(() => { ((dynamic)messageHandler).Handle((dynamic)command); }).ConfigureAwait(false); } if (needReply) { messageReply = _messageQueueClient.WrapMessage(commandContext.Reply, commandContext.MessageID, commandContext.ReplyToEndPoint); eventMessageStates.Add(new MessageState(messageReply)); } eventBus.GetEvents().ForEach(@event => { var topic = @event.GetTopic(); if (!string.IsNullOrEmpty(topic)) { topic = Configuration.Instance.FormatAppName(topic); } var eventContext = _messageQueueClient.WrapMessage(@event, commandContext.MessageID, topic, @event.Key, sagaInfo: sagaInfo); eventMessageStates.Add(new MessageState(eventContext)); }); eventBus.GetToPublishAnywayMessages().ForEach(@event => { var topic = @event.GetTopic(); if (!string.IsNullOrEmpty(topic)) { topic = Configuration.Instance.FormatAppName(topic); } var eventContext = _messageQueueClient.WrapMessage(@event, commandContext.MessageID, topic, @event.Key, sagaInfo: sagaInfo); eventMessageStates.Add(new MessageState(eventContext)); }); messageStore.SaveCommand(commandContext, eventMessageStates.Select(s => s.MessageContext).ToArray()); transactionScope.Complete(); } needRetry = false; } catch (Exception e) { eventMessageStates.Clear(); if (e is OptimisticConcurrencyException && needRetry) { eventBus.ClearMessages(); } else { messageStore.Rollback(); if (needReply) { messageReply = _messageQueueClient.WrapMessage(e.GetBaseException(), commandContext.MessageID, commandContext.ReplyToEndPoint); eventMessageStates.Add(new MessageState(messageReply)); } eventBus.GetToPublishAnywayMessages().ForEach(@event => { var topic = @event.GetTopic(); if (!string.IsNullOrEmpty(topic)) { topic = Configuration.Instance.FormatAppName(topic); } var eventContext = _messageQueueClient.WrapMessage(@event, commandContext.MessageID, topic, @event.Key, sagaInfo: sagaInfo); eventMessageStates.Add(new MessageState(eventContext)); }); if (e is DomainException) { _logger.Warn(command.ToJson(), e); } else { _logger.Error(command.ToJson(), e); } messageStore.SaveFailedCommand(commandContext, e, eventMessageStates.Select(s => s.MessageContext).ToArray()); needRetry = false; } } } while (needRetry); } } try { if (_messagePublisher != null && eventMessageStates.Count > 0) { _messagePublisher.SendAsync(eventMessageStates.ToArray()); } } catch (Exception ex) { _logger.Error($"_messagePublisher SendAsync error", ex); } _removeMessageContext(commandContext); } }
protected async Task ConsumeMessage(IMessageContext eventContext) { var message = eventContext.Message; var sagaInfo = eventContext.SagaInfo; var messageHandlerTypes = _handlerProvider.GetHandlerTypes(message.GetType()); if (messageHandlerTypes.Count == 0) { _removeMessageContext(eventContext); return; } SaveEvent(eventContext); //messageHandlerTypes.ForEach(messageHandlerType => foreach (var messageHandlerType in messageHandlerTypes) { using (var scope = IoCFactory.Instance.CurrentContainer.CreateChildContainer()) { scope.RegisterInstance(typeof(IMessageContext), eventContext); var messageStore = scope.Resolve <IMessageStore>(); var subscriptionName = string.Format("{0}.{1}", _subscriptionName, messageHandlerType.Type.FullName); if (!messageStore.HasEventHandled(eventContext.MessageID, subscriptionName)) { var eventMessageStates = new List <MessageState>(); var commandMessageStates = new List <MessageState>(); var eventBus = scope.Resolve <IEventBus>(); try { var messageHandler = scope.Resolve(messageHandlerType.Type); using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted }, TransactionScopeAsyncFlowOption.Enabled)) { if (messageHandlerType.IsAsync) { await((dynamic)messageHandler).Handle((dynamic)message) .ConfigureAwait(false); } else { await Task.Run(() => { ((dynamic)messageHandler).Handle((dynamic)message); }).ConfigureAwait(false); } //get commands to be sent eventBus.GetCommands().ForEach(cmd => commandMessageStates.Add(new MessageState(_commandBus?.WrapCommand(cmd, sagaInfo: sagaInfo))) ); //get events to be published eventBus.GetEvents().ForEach(msg => { var topic = msg.GetTopic(); if (!string.IsNullOrEmpty(topic)) { topic = Configuration.Instance.FormatAppName(topic); } eventMessageStates.Add(new MessageState(_MessageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo))); }); eventBus.GetToPublishAnywayMessages().ForEach(msg => { var topic = msg.GetTopic(); if (!string.IsNullOrEmpty(topic)) { topic = Configuration.Instance.FormatAppName(topic); } eventMessageStates.Add(new MessageState(_MessageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo))); }); if (sagaInfo != null) { eventBus.GetSagaResults().ForEach(sagaResult => { var topic = sagaInfo.ReplyEndPoint; if (!string.IsNullOrEmpty(topic)) { var sagaReply = _MessageQueueClient.WrapMessage(sagaResult, topic: topic, messageId: ObjectId.GenerateNewId().ToString(), sagaInfo: sagaInfo); eventMessageStates.Add(new MessageState(sagaReply)); } }); } messageStore.HandleEvent(eventContext, subscriptionName, commandMessageStates.Select(s => s.MessageContext), eventMessageStates.Select(s => s.MessageContext)); transactionScope.Complete(); } if (commandMessageStates.Count > 0) { _commandBus?.SendMessageStates(commandMessageStates); } if (eventMessageStates.Count > 0) { _messagePublisher?.SendAsync(eventMessageStates.ToArray()); } } catch (Exception e) { if (e is DomainException) { _logger.Warn(message.ToJson(), e); } else { //IO error or sytem Crash _logger.Error(message.ToJson(), e); } messageStore.Rollback(); eventBus.GetToPublishAnywayMessages().ForEach(msg => { var topic = msg.GetTopic(); if (!string.IsNullOrEmpty(topic)) { topic = Configuration.Instance.FormatAppName(topic); } eventMessageStates.Add(new MessageState(_MessageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo))); }); messageStore.SaveFailHandledEvent(eventContext, subscriptionName, e, eventMessageStates.Select(s => s.MessageContext).ToArray()); if (eventMessageStates.Count > 0) { _messagePublisher?.SendAsync(eventMessageStates.ToArray()); } } } } } _removeMessageContext(eventContext); }
protected virtual async Task ConsumeMessage(IMessageContext commandContext) { Stopwatch watch = Stopwatch.StartNew(); try { var command = commandContext.Message as ICommand; var needReply = !string.IsNullOrEmpty(commandContext.ReplyToEndPoint); var sagaInfo = commandContext.SagaInfo; if (command == null) { InternalConsumer.CommitOffset(commandContext); return; } var needRetry = command.NeedRetry; using (var scope = ObjectProviderFactory.Instance .ObjectProvider .CreateScope(builder => builder.RegisterInstance(typeof(IMessageContext), commandContext))) { using (Logger.BeginScope(new { commandContext.Topic, commandContext.MessageId, commandContext.Key })) { var messageStore = scope.GetService <IMessageStore>(); var eventMessageStates = new List <MessageState>(); var commandHandledInfo = await messageStore.GetCommandHandledInfoAsync(commandContext.MessageId) .ConfigureAwait(false); IMessageContext messageReply = null; if (commandHandledInfo != null) { if (needReply) { messageReply = MessageQueueClient.WrapMessage(commandHandledInfo.Result, commandContext.MessageId, commandContext.ReplyToEndPoint, producer: Producer, messageId: ObjectId.GenerateNewId().ToString()); eventMessageStates.Add(new MessageState(messageReply)); } } else { var eventBus = scope.GetService <IEventBus>(); var messageHandlerType = HandlerProvider.GetHandlerTypes(command.GetType()).FirstOrDefault(); Logger.LogInformation("Handle command, commandID:{0}", commandContext.MessageId); if (messageHandlerType == null) { Logger.LogDebug($"command has no handlerTypes, message:{command.ToJson()}"); if (needReply) { messageReply = MessageQueueClient.WrapMessage(new NoHandlerExists(), commandContext.MessageId, commandContext.ReplyToEndPoint, producer: Producer); eventMessageStates.Add(new MessageState(messageReply)); } } else { object messageHandler = null; do { try { if (messageHandler == null) { messageHandler = scope.GetRequiredService(messageHandlerType.Type); } using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) { if (messageHandlerType.IsAsync) { await((dynamic)messageHandler).Handle((dynamic)command) .ConfigureAwait(false); } else { var handler = messageHandler; await Task.Run(() => { ((dynamic)handler).Handle((dynamic)command); }).ConfigureAwait(false); } if (needReply) { messageReply = MessageQueueClient.WrapMessage(commandContext.Reply, commandContext.MessageId, commandContext.ReplyToEndPoint, producer: Producer); eventMessageStates.Add(new MessageState(messageReply)); } eventBus.GetEvents() .ForEach(@event => { var topic = @event.GetFormatTopic(); var eventContext = MessageQueueClient.WrapMessage(@event, commandContext.MessageId, topic, @event.Key, sagaInfo: sagaInfo, producer: Producer); eventMessageStates.Add(new MessageState(eventContext)); }); eventBus.GetToPublishAnywayMessages() .ForEach(@event => { var topic = @event.GetFormatTopic(); var eventContext = MessageQueueClient.WrapMessage(@event, commandContext.MessageId, topic, @event.Key, sagaInfo: sagaInfo, producer: Producer); eventMessageStates.Add(new MessageState(eventContext)); }); eventMessageStates.AddRange(GetSagaReplyMessageStates(sagaInfo, eventBus)); await messageStore.SaveCommandAsync(commandContext, commandContext.Reply, eventMessageStates.Select(s => s.MessageContext).ToArray()) .ConfigureAwait(false); transactionScope.Complete(); } needRetry = false; } catch (Exception e) { eventMessageStates.Clear(); messageStore.Rollback(); if (e is DBConcurrencyException && needRetry) { eventBus.ClearMessages(); } else { if (needReply) { messageReply = MessageQueueClient.WrapMessage(e, commandContext.MessageId, commandContext.ReplyToEndPoint, producer: Producer, messageId: ObjectId.GenerateNewId().ToString()); eventMessageStates.Add(new MessageState(messageReply)); } eventBus.GetToPublishAnywayMessages() .ForEach(@event => { var topic = @event.GetFormatTopic(); var eventContext = MessageQueueClient.WrapMessage(@event, commandContext.MessageId, topic, @event.Key, sagaInfo: sagaInfo, producer: Producer); eventMessageStates.Add(new MessageState(eventContext)); }); if (e is DomainException exception) { var domainExceptionEvent = exception.DomainExceptionEvent; if (domainExceptionEvent != null) { var topic = domainExceptionEvent.GetFormatTopic(); var exceptionMessage = MessageQueueClient.WrapMessage(domainExceptionEvent, commandContext.MessageId, topic, producer: Producer); eventMessageStates.Add(new MessageState(exceptionMessage)); } Logger.LogWarning(e, command.ToJson()); } else { Logger.LogError(e, command.ToJson()); //if we meet with unknown exception, we interrupt saga if (sagaInfo != null) { eventBus.FinishSaga(e); } } eventMessageStates.AddRange(GetSagaReplyMessageStates(sagaInfo, eventBus)); await messageStore.SaveFailedCommandAsync(commandContext, e, eventMessageStates.Select(s => s.MessageContext) .ToArray()) .ConfigureAwait(false); needRetry = false; } } } while (needRetry); } } if (eventMessageStates.Count > 0) { var sendTask = MessagePublisher.SendAsync(CancellationToken.None, eventMessageStates.ToArray()); // we don't need to wait the send task complete here. } } } } catch (Exception ex) { Logger.LogCritical(ex, $"{ConsumerId} CommandProcessor consume command failed"); } finally { watch.Stop(); Logger.LogDebug($"{commandContext.ToJson()} consumed cost:{watch.ElapsedMilliseconds}ms"); } InternalConsumer.CommitOffset(commandContext); }
protected virtual async Task ConsumeMessage(IMessageContext commandContext) { try { var command = commandContext.Message as ICommand; var needReply = !string.IsNullOrEmpty(commandContext.ReplyToEndPoint); var sagaInfo = commandContext.SagaInfo; IMessageContext messageReply = null; if (command == null) { _internalConsumer.CommitOffset(commandContext); return; } var needRetry = command.NeedRetry; using (var scope = IoCFactory.Instance.CurrentContainer.CreateChildContainer()) { scope.RegisterInstance(typeof(IMessageContext), commandContext); var messageStore = scope.Resolve <IMessageStore>(); var eventMessageStates = new List <MessageState>(); var commandHandledInfo = messageStore.GetCommandHandledInfo(commandContext.MessageID); if (commandHandledInfo != null) { if (needReply) { messageReply = _messageQueueClient.WrapMessage(commandHandledInfo.Result, commandContext.MessageID, commandContext.ReplyToEndPoint, producer: Producer, messageId: ObjectId.GenerateNewId().ToString()); eventMessageStates.Add(new MessageState(messageReply)); } } else { var eventBus = scope.Resolve <IEventBus>(); var messageHandlerType = _handlerProvider.GetHandlerTypes(command.GetType()).FirstOrDefault(); _logger?.InfoFormat("Handle command, commandID:{0}", commandContext.MessageID); if (messageHandlerType == null) { _logger?.Debug($"command has no handlerTypes, message:{command.ToJson()}"); if (needReply) { messageReply = _messageQueueClient.WrapMessage(new NoHandlerExists(), commandContext.MessageID, commandContext.ReplyToEndPoint, producer: Producer); eventMessageStates.Add(new MessageState(messageReply)); } } else { object messageHandler = null; do { try { if (messageHandler == null) { messageHandler = scope.Resolve(messageHandlerType.Type); } using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) { if (messageHandlerType.IsAsync) { await((dynamic)messageHandler).Handle((dynamic)command) .ConfigureAwait(false); } else { var handler = messageHandler; await Task.Run(() => { ((dynamic)handler).Handle((dynamic)command); }).ConfigureAwait(false); } if (needReply) { messageReply = _messageQueueClient.WrapMessage(commandContext.Reply, commandContext.MessageID, commandContext.ReplyToEndPoint, producer: Producer); eventMessageStates.Add(new MessageState(messageReply)); } eventBus.GetEvents() .ForEach(@event => { var topic = @event.GetFormatTopic(); var eventContext = _messageQueueClient.WrapMessage(@event, commandContext.MessageID, topic, @event.Key, sagaInfo: sagaInfo, producer: Producer); eventMessageStates.Add(new MessageState(eventContext)); }); eventBus.GetToPublishAnywayMessages() .ForEach(@event => { var topic = @event.GetFormatTopic(); var eventContext = _messageQueueClient.WrapMessage(@event, commandContext.MessageID, topic, @event.Key, sagaInfo: sagaInfo, producer: Producer); eventMessageStates.Add(new MessageState(eventContext)); }); eventMessageStates.AddRange(GetSagaReplyMessageStates(sagaInfo, eventBus)); messageStore.SaveCommand(commandContext, commandContext.Reply, eventMessageStates.Select(s => s.MessageContext).ToArray()); transactionScope.Complete(); } needRetry = false; } catch (Exception e) { eventMessageStates.Clear(); messageStore.Rollback(); if (e is OptimisticConcurrencyException && needRetry) { eventBus.ClearMessages(); } else { if (needReply) { messageReply = _messageQueueClient.WrapMessage(e.GetBaseException(), commandContext.MessageID, commandContext.ReplyToEndPoint, producer: Producer, messageId: ObjectId.GenerateNewId().ToString()); eventMessageStates.Add(new MessageState(messageReply)); } eventBus.GetToPublishAnywayMessages() .ForEach(@event => { var topic = @event.GetFormatTopic(); var eventContext = _messageQueueClient.WrapMessage(@event, commandContext.MessageID, topic, @event.Key, sagaInfo: sagaInfo, producer: Producer); eventMessageStates.Add(new MessageState(eventContext)); }); if (e is DomainException exception) { var domainExceptionEvent = exception.DomainExceptionEvent; if (domainExceptionEvent != null) { var topic = domainExceptionEvent.GetFormatTopic(); var exceptionMessage = _messageQueueClient.WrapMessage(domainExceptionEvent, commandContext.MessageID, topic, producer: Producer); eventMessageStates.Add(new MessageState(exceptionMessage)); } _logger?.Warn(command.ToJson(), e); } else { _logger?.Error(command.ToJson(), e); //if we meet with unknown exception, we interrupt saga if (sagaInfo != null) { eventBus.FinishSaga(e); } } eventMessageStates.AddRange(GetSagaReplyMessageStates(sagaInfo, eventBus)); messageStore.SaveFailedCommand(commandContext, e, eventMessageStates.Select(s => s.MessageContext).ToArray()); needRetry = false; } } } while (needRetry); } } if (eventMessageStates.Count > 0) { var sendTask = _messagePublisher.SendAsync(eventMessageStates.ToArray()); // we don't need to wait the send task complete here. } } } catch (Exception ex) { _logger?.Fatal($"consume command failed", ex); } _internalConsumer.CommitOffset(commandContext); }
protected void ConsumeMessage(IMessageContext eventContext) { var message = eventContext.Message; var messageHandlerTypes = _handlerProvider.GetHandlerTypes(message.GetType()); if (messageHandlerTypes.Count == 0) { return; } messageHandlerTypes.ForEach(messageHandlerType => { PerMessageContextLifetimeManager.CurrentMessageContext = eventContext; eventContext.ToBeSentMessageContexts.Clear(); var messageStore = IoCFactory.Resolve <IMessageStore>(); var subscriptionName = string.Format("{0}.{1}", _subscriptionName, messageHandlerType.FullName); if (!messageStore.HasEventHandled(eventContext.MessageID, subscriptionName)) { bool success = false; var messageContexts = new List <IMessageContext>(); List <IMessageContext> commandContexts = null; try { var messageHandler = IoCFactory.Resolve(messageHandlerType); using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted })) { ((dynamic)messageHandler).Handle((dynamic)message); //get commands to be sent commandContexts = eventContext.ToBeSentMessageContexts; //get events to be published var eventBus = IoCFactory.Resolve <IEventBus>(); eventBus.GetMessages().ForEach(msg => messageContexts.Add(_MessageQueueClient.WrapMessage(msg))); messageStore.SaveEvent(eventContext, subscriptionName, commandContexts, messageContexts); transactionScope.Complete(); } success = true; } catch (Exception e) { if (e is DomainException) { _logger.Warn(message.ToJson(), e); } else { //IO error or sytem Crash _logger.Error(message.ToJson(), e); } messageStore.SaveFailHandledEvent(eventContext, subscriptionName, e); } if (success) { if (commandContexts.Count > 0) { _commandBus.Send(commandContexts.AsEnumerable()); } if (messageContexts.Count > 0) { _messagePublisher.Send(messageContexts.ToArray()); } } } PerMessageContextLifetimeManager.CurrentMessageContext = null; }); }
protected async Task ConsumeMessage(IMessageContext eventContext) { try { Logger.LogDebug($"start handle event {ConsumerId} {eventContext.Message.ToJson()}"); var message = eventContext.Message; if (message == null) { Logger.LogDebug($"message is null! messageContext: {eventContext.ToJson()}"); return; } var sagaInfo = eventContext.SagaInfo; var messageHandlerTypes = HandlerProvider.GetHandlerTypes(message.GetType()); if (messageHandlerTypes.Count == 0) { Logger.LogDebug($"event has no handlerTypes, messageType:{message.GetType()} message:{message.ToJson()}"); return; } //messageHandlerTypes.ForEach(messageHandlerType => foreach (var messageHandlerType in messageHandlerTypes) { using (var scope = ObjectProviderFactory.Instance .ObjectProvider .CreateScope(builder => builder.RegisterInstance(typeof(IMessageContext), eventContext))) { var messageStore = scope.GetService <IMessageStore>(); var subscriptionName = $"{SubscriptionName}.{messageHandlerType.Type.FullName}"; using (Logger.BeginScope(new { eventContext.Topic, eventContext.MessageId, eventContext.Key, subscriptionName })) { var eventMessageStates = new List <MessageState>(); var commandMessageStates = new List <MessageState>(); var eventBus = scope.GetService <IEventBus>(); try { if (!await messageStore.HasEventHandledAsync(eventContext.MessageId, subscriptionName) .ConfigureAwait(false)) { var messageHandler = scope.GetRequiredService(messageHandlerType.Type); using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }, TransactionScopeAsyncFlowOption.Enabled)) { if (messageHandlerType.IsAsync) { await((dynamic)messageHandler).Handle((dynamic)message) .ConfigureAwait(false); } else { ((dynamic)messageHandler).Handle((dynamic)message); } //get commands to be sent eventBus.GetCommands() .ForEach(cmd => commandMessageStates.Add(new MessageState(CommandBus?.WrapCommand(cmd, sagaInfo: sagaInfo, producer: Producer))) ); //get events to be published eventBus.GetEvents() .ForEach(msg => { var topic = msg.GetFormatTopic(); eventMessageStates.Add(new MessageState(MessageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo, producer: Producer))); }); eventBus.GetToPublishAnywayMessages() .ForEach(msg => { var topic = msg.GetFormatTopic(); eventMessageStates.Add(new MessageState(MessageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo, producer: Producer))); }); eventMessageStates.AddRange(GetSagaReplyMessageStates(sagaInfo, eventBus)); await messageStore.HandleEventAsync(eventContext, subscriptionName, commandMessageStates.Select(s => s.MessageContext), eventMessageStates.Select(s => s.MessageContext)) .ConfigureAwait(false); transactionScope.Complete(); } if (commandMessageStates.Count > 0) { CommandBus?.SendMessageStates(commandMessageStates); } if (eventMessageStates.Count > 0) { MessagePublisher?.SendAsync(CancellationToken.None, eventMessageStates.ToArray()); } } } catch (Exception e) { eventMessageStates.Clear(); messageStore.Rollback(); if (e is DomainException exception) { var domainExceptionEvent = exception.DomainExceptionEvent; if (domainExceptionEvent != null) { var topic = domainExceptionEvent.GetFormatTopic(); var exceptionMessage = MessageQueueClient.WrapMessage(domainExceptionEvent, eventContext.MessageId, topic, producer: Producer); eventMessageStates.Add(new MessageState(exceptionMessage)); } Logger.LogWarning(e, message.ToJson()); } else { //IO error or sytem Crash //if we meet with unknown exception, we interrupt saga if (sagaInfo != null) { eventBus.FinishSaga(e); } Logger.LogError(e, message.ToJson()); } eventBus.GetToPublishAnywayMessages() .ForEach(msg => { var topic = msg.GetFormatTopic(); eventMessageStates.Add(new MessageState(MessageQueueClient.WrapMessage(msg, topic: topic, key: msg.Key, sagaInfo: sagaInfo, producer: Producer))); }); eventMessageStates.AddRange(GetSagaReplyMessageStates(sagaInfo, eventBus)); await messageStore.SaveFailHandledEventAsync(eventContext, subscriptionName, e, eventMessageStates.Select(s => s.MessageContext).ToArray()) .ConfigureAwait(false); if (eventMessageStates.Count > 0) { var sendTask = MessagePublisher.SendAsync(CancellationToken.None, eventMessageStates.ToArray()); } } } } } } catch (Exception e) { Logger.LogCritical(e, $"Handle event failed event: {eventContext.ToJson()}"); } finally { InternalConsumer.CommitOffset(eventContext); } }