Ejemplo n.º 1
0
 protected Task ConsumeReply(IMessageContext reply)
 {
     try
     {
         Logger.LogInformation("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 exception)
             {
                 messageState.ReplyTaskCompletionSource.TrySetException(exception);
             }
             else
             {
                 messageState.ReplyTaskCompletionSource.TrySetResult(reply.Message);
             }
         }
     }
     catch (Exception e)
     {
         Logger.LogError(e);
     }
     finally
     {
         _internalConsumer.CommitOffset(reply);
     }
     return(Task.CompletedTask);
 }
Ejemplo n.º 2
0
        protected async Task ConsumeMessage(IMessageContext eventContext)
        {
            try
            {
                Logger.LogDebug($"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.LogDebug($"event has no handlerTypes, messageType:{message.GetType()} message:{message.ToJson()}");
                    InternalConsumer.CommitOffset(eventContext);
                    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
                        }))
                        {
                            if (!messageStore.HasEventHandled(eventContext.MessageId, subscriptionName))
                            {
                                var eventMessageStates   = new List <MessageState>();
                                var commandMessageStates = new List <MessageState>();
                                var eventBus             = scope.GetService <IEventBus>();
                                try
                                {
                                    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
                                        {
                                            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(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));

                                    messageStore.SaveFailHandledEvent(eventContext, subscriptionName, e,
                                                                      eventMessageStates.Select(s => s.MessageContext).ToArray());
                                    if (eventMessageStates.Count > 0)
                                    {
                                        MessagePublisher?.SendAsync(CancellationToken.None, eventMessageStates.ToArray());
                                    }
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Logger.LogCritical(e, $"Handle event failed event: {eventContext.ToJson()}");
            }

            InternalConsumer.CommitOffset(eventContext);
        }
Ejemplo n.º 3
0
        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);
        }