Esempio n. 1
0
 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);
 }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }