protected async Task ConsumeReply(IMessageContext reply) { await Task.Run(() => { _logger?.InfoFormat("Handle reply:{0} content:{1}", reply.MessageID, reply.ToJson()); var sagaInfo = reply.SagaInfo; var correlationID = sagaInfo?.SagaId ?? reply.CorrelationID; var messageState = _commandStateQueues.TryGetValue(correlationID); if (messageState != null) { _commandStateQueues.TryRemove(correlationID); if (reply.Message is Exception) { messageState.ReplyTaskCompletionSource.TrySetException(reply.Message as Exception); } else { messageState.ReplyTaskCompletionSource.TrySetResult(reply.Message); } } _internalConsumer.CommitOffset(reply); }) .ConfigureAwait(false); }
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 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); }