예제 #1
0
        /// <summary>
        /// 处理消息队列的消息
        /// </summary>
        /// <param name="currentConsumer"></param>
        /// <param name="props"></param>
        /// <param name="exchangeName"></param>
        /// <param name="queueName"></param>
        /// <param name="routingKey"></param>
        /// <param name="body"></param>
        /// <param name="deliveryTag"></param>
        /// <param name="redelivered"></param>
        /// <param name="dropIfMessageHandlerNotRegistered">消息处理器未注册时直接丢弃</param>
        protected void HandleMessage(IBasicConsumer currentConsumer, IBasicProperties props, string exchangeName, string queueName, string routingKey, byte[] body, ulong deliveryTag, bool redelivered, bool dropIfMessageHandlerNotRegistered)
        {
            var currentChannel  = currentConsumer.Model;
            var messageTypeName = props.Type;

            if (string.IsNullOrEmpty(props.Type))
            {
                // 如果未传入类型,则以队列名作为类型名
                if (queueName.StartsWith("rpc."))
                {
                    messageTypeName = queueName.Substring(4);
                }
                else
                {
                    messageTypeName = queueName;
                }
            }
            var context = new MessageHandlingTransportationContext(exchangeName, queueName, new Dictionary <string, object> {
                { MessagePropertyConstants.MESSAGE_ID, string.IsNullOrEmpty(props.MessageId) ? Guid.NewGuid().ToString() : props.MessageId },
                { MessagePropertyConstants.MESSAGE_TYPE, messageTypeName },
                { MessagePropertyConstants.TIMESTAMP, props.Timestamp.UnixTime == 0 ? DateTime.Now : DateTime2UnixTime.FromUnixTime(props.Timestamp.UnixTime) },
                { MessagePropertyConstants.CONTENT_TYPE, string.IsNullOrEmpty(props.ContentType) ? Serializer.ContentType : props.ContentType },
                { MessagePropertyConstants.PAYLOAD, Serializer.GetString(body) },
                { MessagePropertyConstants.ROUTING_KEY, routingKey },
                { MessagePropertyConstants.REPLY_TO, props.ReplyTo },
                { MessagePropertyConstants.CORRELATION_ID, props.CorrelationId }
            });
            var messageHandlerCategory = string.Empty;

            try
            {
                if (_messageTypes.ContainsKey(messageTypeName))
                {
                    object message = null;
                    try
                    {
                        message = Serializer.Deserialize(body, _messageTypes[messageTypeName]);
                    }
                    catch
                    {
                        // 消费端无法反序列化消息,则直接丢弃
                        _logger.Error($"Message [\"{context.GetMessageType()}\"] \"{context.GetPayload()}\" deserialized fail in queue \"{queueName}\".");
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicReject(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }

                    if (message == null)
                    {
                        return;
                    }
                    var messageHandler = GetMessageHandler(messageTypeName);
                    if (messageHandler != null)
                    {
                        messageHandlerCategory = MessageHandlerTypeAttribute.GetCategory(messageHandler.GetType());
                        TriggerOnMessageReceived(new MessageReceivedEventArgs(messageHandlerCategory, this.GetReceiverType(), context));
                        RetryPolicy.Retry(() =>
                        {
                            try
                            {
                                messageHandler.GetType().InvokeMember("Handle",
                                                                      BindingFlags.InvokeMethod
                                                                      | BindingFlags.Public
                                                                      | BindingFlags.Instance,
                                                                      null, messageHandler, new object[] { message, context });
                            }
                            catch (Exception handleEx)
                            {
                                context.LastException = handleEx is TargetInvocationException ? handleEx.InnerException : handleEx;
                                throw handleEx;
                            }
                        }, cancelOnFailed: (retryCount, retryException) =>
                        {
                            if (retryCount >= MaxRetryCount)
                            {
                                return(true);
                            }
                            context.LastException = retryException is TargetInvocationException ? retryException.InnerException : retryException;
                            context.RetryCount    = retryCount + 1;
                            return(false);
                        });

                        TriggerOnMessageHandlingSucceeded(new MessageHandlingSucceededEventArgs(messageHandlerCategory, this.GetReceiverType(), context));
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }
                    else if (dropIfMessageHandlerNotRegistered)
                    {
                        // 消费端无对应的消息处理器,则忽略,直接响应成功
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }
                    else
                    {
                        context.LastException = new MessageHandlerNotRegisteredException(messageTypeName);
                        if (TriggerOnMessageHandlingFailed(new MessageHandlingFailedEventArgs(messageHandlerCategory, this.GetReceiverType(), context)))
                        {
                            LockerExecuter.Execute(currentChannel, () =>
                            {
                                RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                                  retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                                  retryTimeInterval: 1000);
                            });
                        }
                        else
                        {
                            LockerExecuter.Execute(currentChannel, () =>
                            {
                                RetryPolicy.Retry(() => currentChannel.BasicReject(deliveryTag, false),
                                                  retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                                  retryTimeInterval: 1000);
                            });
                        }
                    }
                }
                else if (dropIfMessageHandlerNotRegistered)
                {
                    // 消费端无对应的消息处理器,则忽略,直接响应成功
                    LockerExecuter.Execute(currentChannel, () =>
                    {
                        RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                          retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                          retryTimeInterval: 1000);
                    });
                }
                else
                {
                    context.LastException = new MessageHandlerNotRegisteredException(messageTypeName);
                    if (TriggerOnMessageHandlingFailed(new MessageHandlingFailedEventArgs(messageHandlerCategory, this.GetReceiverType(), context)))
                    {
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }
                    else
                    {
                        LockerExecuter.Execute(currentChannel, () =>
                        {
                            RetryPolicy.Retry(() => currentChannel.BasicReject(deliveryTag, false),
                                              retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                              retryTimeInterval: 1000);
                        });
                    }
                }
            }
            catch (Exception ex)
            {
                // 消费端处理其他异常
                context.LastException = ex is TargetInvocationException ? ex.InnerException : ex;
                if (TriggerOnMessageHandlingFailed(new MessageHandlingFailedEventArgs(messageHandlerCategory, this.GetReceiverType(), context)))
                {
                    LockerExecuter.Execute(currentChannel, () =>
                    {
                        RetryPolicy.Retry(() => currentChannel.BasicAck(deliveryTag, false),
                                          retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                          retryTimeInterval: 1000);
                    });
                }
                else
                {
                    LockerExecuter.Execute(currentChannel, () =>
                    {
                        RetryPolicy.Retry(() => currentChannel.BasicReject(deliveryTag, false),
                                          retryCondition: retryEx => IOHelper.IsIOError(retryEx) || RabbitMQExceptionHelper.IsChannelError(retryEx),
                                          retryTimeInterval: 1000);
                    });
                }
            }
        }
예제 #2
0
        /// <summary>
        /// 订阅指定队列
        /// </summary>
        public void Subscribe()
        {
            var exceptionList = new List <Exception>();

            foreach (var channel in _channels)
            {
                if (_consumers.Exists(e => e.Model == channel))
                {
                    continue;
                }
                var consumer = new EventingBasicConsumer(channel);
                try
                {
                    consumer.Received += (sender, e) =>
                    {
                        var currentConsumer = ((EventingBasicConsumer)sender);
                        var currentChannel  = currentConsumer.Model;
                        HandleMessage(currentConsumer, e.BasicProperties, e.Exchange, QueueName, e.RoutingKey, e.Body, e.DeliveryTag, e.Redelivered, false);
                    };

                    consumer.Shutdown += (sender, e) =>
                    {
                        var currentConsumer = ((EventingBasicConsumer)sender);
                        var currentChannel  = currentConsumer.Model;
                        _logger.Warn($"PubsubReceiver.Consumer.Shutdown: QueueName={QueueName}, ChannelIsOpen={currentChannel.IsOpen}, Initiator={e.Initiator}, ClassId={e.ClassId}, MethodId={e.MethodId}, ReplyCode={e.ReplyCode}, ReplyText={e.ReplyText}");
                        while (RabbitMQExceptionHelper.IsChannelError(e.ReplyCode) && !currentChannel.IsOpen)
                        {
                            Thread.Sleep(1000);
                        }
                    };

                    LockerExecuter.Execute(channel, () =>
                    {
                        try
                        {
                            RetryPolicy.Retry(() => channel.BasicConsume(QueueName, false, consumer),
                                              retryCondition: ex => IOHelper.IsIOError(ex) || RabbitMQExceptionHelper.IsChannelError(ex),
                                              maxRetryCount: 1,
                                              retryTimeInterval: 1000);
                        }
                        catch (Exception ex)
                        {
                            var realEx = ex is TargetInvocationException ? ex.InnerException : ex;
                            _logger.Error(realEx.Message, realEx);
                            throw new TargetException(realEx.Message, realEx);
                        }
                    });
                }
                catch (Exception ex)
                {
                    exceptionList.Add(ex);
                }
                finally
                {
                    _consumers.Add(consumer);
                }
            }
            if (exceptionList.Count > 0)
            {
                throw new AggregateException(exceptionList);
            }
        }
예제 #3
0
        /// <summary>
        /// 接收请求
        /// </summary>
        public void ReceiveRequest()
        {
            var exceptionList = new List <Exception>();

            foreach (var methodName in MethodNameList)
            {
                var queueName         = _disableQueuePrefix ? methodName : $"rpc.{methodName}";
                var callbackQueueName = $"{queueName}.callback";
                var channelList       = _channels[methodName];
                _consumers.TryGetValue(queueName, out List <EventingBasicConsumer> consumers);
                if (consumers == null)
                {
                    consumers = new List <EventingBasicConsumer>();
                }
                foreach (var channel in channelList)
                {
                    if (consumers.Exists(e => e.Model == channel))
                    {
                        continue;
                    }
                    var consumer = new EventingBasicConsumer(channel);
                    try
                    {
                        consumer.Received += (sender, e) =>
                        {
                            var currentConsumer = ((EventingBasicConsumer)sender);
                            var currentChannel  = currentConsumer.Model;
                            while (!_channels.Any(w => w.Value.Contains(currentChannel)))
                            {
                                Thread.Sleep(1000);
                            }
                            var currentMethodName = _channels.First(w => w.Value.Contains(currentChannel)).Key;
                            var currentQueueName  = _disableQueuePrefix ? currentMethodName : $"rpc.{currentMethodName}";
                            HandleMessage(currentConsumer, e.BasicProperties, e.Exchange, currentQueueName, e.RoutingKey, e.Body, e.DeliveryTag, e.Redelivered, false);
                        };

                        consumer.Shutdown += (sender, e) =>
                        {
                            var currentConsumer = ((EventingBasicConsumer)sender);
                            var currentChannel  = currentConsumer.Model;
                            while (!_channels.Any(w => w.Value.Contains(currentChannel)))
                            {
                                Thread.Sleep(1000);
                            }
                            var currentMethodName = _channels.First(w => w.Value.Contains(currentChannel)).Key;
                            var currentQueueName  = _disableQueuePrefix ? currentMethodName : $"rpc.{currentMethodName}";
                            _logger.Warn($"RpcServer.Consumer.Shutdown: QueueName={currentQueueName}, ChannelIsOpen={currentChannel.IsOpen}, Initiator={e.Initiator}, ClassId={e.ClassId}, MethodId={e.MethodId}, ReplyCode={e.ReplyCode}, ReplyText={e.ReplyText}");
                            while (RabbitMQExceptionHelper.IsChannelError(e.ReplyCode) && !currentChannel.IsOpen)
                            {
                                Thread.Sleep(1000);
                            }
                        };

                        LockerExecuter.Execute(channel, () =>
                        {
                            try
                            {
                                RetryPolicy.Retry(() => channel.BasicConsume(queueName, false, consumer),
                                                  retryCondition: ex => IOHelper.IsIOError(ex) || RabbitMQExceptionHelper.IsChannelError(ex),
                                                  maxRetryCount: 1,
                                                  retryTimeInterval: 1000);
                            }
                            catch (Exception ex)
                            {
                                var realEx = ex is TargetInvocationException ? ex.InnerException : ex;
                                _logger.Error(realEx.Message, realEx);
                                throw new TargetException(realEx.Message, realEx);
                            }
                        });
                    }
                    catch (Exception ex)
                    {
                        exceptionList.Add(ex);
                    }
                    finally
                    {
                        consumers.Add(consumer);
                    }
                }
                _consumers.TryAdd(queueName, consumers);
            }
            if (exceptionList.Count > 0)
            {
                throw new AggregateException(exceptionList);
            }
        }
예제 #4
0
        /// <summary>
        /// 订阅指定队列
        /// </summary>
        /// <param name="queueIndex">队列索引</param>
        public void Subscribe(byte queueIndex)
        {
            if (_isDisposing)
            {
                throw new ObjectDisposedException(nameof(TopicReceiver));
            }
            if (queueIndex >= QueueCount)
            {
                throw new ArgumentOutOfRangeException("queueIndex", $"must less than {QueueCount}");
            }
            var    dlxQueueName = $"{ExchangeName}-dlx";
            string queueName    = $"{ExchangeName}-{queueIndex}";

            using (var channelForConfig = _conn.CreateChannel())
            {
                _conn.DeclareQueue(channelForConfig, queueName, new Dictionary <string, object> {
                    { "x-dead-letter-exchange", "" },
                    { "x-dead-letter-routing-key", dlxQueueName },
                });
                channelForConfig.Close();
            }

            _consumers.TryGetValue(queueIndex, out EventingBasicConsumer consumer);
            if (consumer != null)
            {
                return;
            }

            _channels.TryGetValue(queueIndex, out IModel channel);
            if (channel == null)
            {
                channel = _conn.CreateChannel();
                channel.BasicQos(0, 1, false);
            }
            consumer = new EventingBasicConsumer(channel);

            try
            {
                consumer.Received += (sender, e) =>
                {
                    var currentConsumer = ((EventingBasicConsumer)sender);
                    var currentChannel  = currentConsumer.Model;
                    while (!_channels.Any(w => w.Value == currentChannel))
                    {
                        Thread.Sleep(1000);
                    }
                    var currentQueueIndex = _channels.First(w => w.Value == currentChannel).Key;
                    var currentQueueName  = $"{ExchangeName}-{currentQueueIndex}";
                    HandleMessage(currentConsumer, e.BasicProperties, e.Exchange, currentQueueName, e.RoutingKey, e.Body, e.DeliveryTag, e.Redelivered, true);
                };

                consumer.Shutdown += (sender, e) =>
                {
                    var currentConsumer = ((EventingBasicConsumer)sender);
                    var currentChannel  = currentConsumer.Model;
                    while (!_channels.Any(w => w.Value == currentChannel))
                    {
                        Thread.Sleep(1000);
                    }
                    var currentQueueIndex = _channels.First(w => w.Value == currentChannel).Key;
                    var currentQueueName  = $"{ExchangeName}-{currentQueueIndex}";
                    _logger.Warn($"TopicReceiver.Consumer.Shutdown: ExchangeName={ExchangeName}, QueueName={currentQueueName}, ChannelIsOpen={currentChannel.IsOpen}, Initiator={e.Initiator}, ClassId={e.ClassId}, MethodId={e.MethodId}, ReplyCode={e.ReplyCode}, ReplyText={e.ReplyText}");
                    while (RabbitMQExceptionHelper.IsChannelError(e.ReplyCode) && !currentChannel.IsOpen)
                    {
                        Thread.Sleep(1000);
                    }
                };

                LockerExecuter.Execute(channel, () =>
                {
                    try
                    {
                        RetryPolicy.Retry(() => channel.BasicConsume(queueName, false, consumer),
                                          retryCondition: ex => IOHelper.IsIOError(ex) || RabbitMQExceptionHelper.IsChannelError(ex),
                                          maxRetryCount: 1,
                                          retryTimeInterval: 1000);
                    }
                    catch (Exception ex)
                    {
                        var realEx = ex is TargetInvocationException ? ex.InnerException : ex;
                        _logger.Error(realEx.Message, realEx);
                        throw new TargetException(realEx.Message, realEx);
                    }
                });
            }
            finally
            {
                _channels.TryAdd(queueIndex, channel);
                _consumers.TryAdd(queueIndex, consumer);
            }
        }