Ejemplo n.º 1
0
        /// <summary>
        /// 发现并绑定消费者
        /// </summary>
        public virtual void BindConsumer()
        {
            var consumers = MqConsumerDispatcher.DiscoverConsumers();

            foreach (var consumer in consumers)
            {
                this.Received(consumer);
            }
        }
Ejemplo n.º 2
0
        protected virtual void Received(MqConsumerExecutor consumerExecutor)
        {
            if (consumerExecutor == null || string.IsNullOrWhiteSpace(consumerExecutor?.RouteName))
            {
                throw new ArgumentException("Received(consumerExecutor)不能为空");
            }

            string exchangeName = consumerExecutor.RouteName;
            string queueName    = consumerExecutor.RouteName;

            try
            {
                var channel = RabbitMQManager.Connection.CreateModel();

                channel.ExchangeDeclare(exchange: exchangeName, type: RabbitMQExchangeType.Direct, durable: true, autoDelete: false, arguments: null);
                channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false, arguments: null);
                channel.QueueBind(queue: queueName, exchange: exchangeName, routingKey: queueName);

                //进行消费端的限流,限流情况autoAck不能设置为true自动签收,一定要手动签收
                if (!consumerExecutor.AutoAck)
                {
                    channel.BasicQos(prefetchSize: consumerExecutor.PrefetchSize, prefetchCount: consumerExecutor.PrefetchCount, global: false);
                }

                var consumer = new EventingBasicConsumer(channel);

                consumer.Received += async(sender, eventArgs) =>
                {
                    MqConsumerExecutedResult result = null;
                    string msgJson = string.Empty;

                    try
                    {
                        if (eventArgs.Body.IsEmpty)
                        {
                            channel.BasicAck(deliveryTag: eventArgs.DeliveryTag, multiple: false);
                        }

                        msgJson = Encoding.UTF8.GetString(eventArgs.Body.ToArray());

                        result = await MqConsumerDispatcher.InvokeAsync(consumerExecutor, msgJson);
                    }
                    catch (Exception ex)
                    {
                        var traceInfo = new { ConsumerExecutor = consumerExecutor, MsgJson = msgJson };

                        LogHelper.Error(ex, $"消费者执行异常:{msgJson}", filename: $"RabbitMQ_{queueName}_Exception");
                    }
                    finally
                    {
                        var traceInfo = new { ConsumerExecutor = consumerExecutor, MsgJson = msgJson };

                        if (result == null || !result.ReplyType.IsInDefined())
                        {
                            LogHelper.Error($"消费者未回馈消息处理情况:{msgJson}", filename: $"RabbitMQ_{queueName}_Unknown");

                            channel.BasicNack(deliveryTag: eventArgs.DeliveryTag, multiple: false, requeue: false);
                        }
                        else
                        {
                            if (result.ReplyType != MqReplyType.Ack)
                            {
                                LogHelper.Trace($"消费者处理情况:{msgJson}", filename: $"RabbitMQ_{queueName}_{result.ReplyType.ToString()}");
                            }

                            if (result.ReplyType == MqReplyType.Ack)
                            {
                                //发送确认信号,告诉MQ这个消息处理成功,可以从队列移除此消息
                                //同一个会话consumerTag是固定的名字,deliveryTag每次接收消息会+1
                                channel.BasicAck(deliveryTag: eventArgs.DeliveryTag, multiple: false);
                            }
                            else if (result.ReplyType == MqReplyType.Nack)
                            {
                                //发送不确认信号,该消息会从队列移除(若IsRequeue设置为true,那么消息会重新投递到队列头部)
                                //BasicNack第二个参数multiple是否应用于多消息,与BasicReject区别就是同时支持多个消息,可以nack该消费者先前接收未ack的所有消息
                                channel.BasicNack(deliveryTag: eventArgs.DeliveryTag, multiple: false, requeue: result.IsRequeue);
                            }
                            else if (result.ReplyType == MqReplyType.Reject)
                            {
                                //发送拒绝信号,该消息会从队列清除移除(若IsRequeue设置为true,那么消息会重新投递到队列头部)
                                channel.BasicReject(deliveryTag: eventArgs.DeliveryTag, requeue: result.IsRequeue);
                            }
                        }
                    }
                };

                channel.BasicConsume(queue: queueName, autoAck: consumerExecutor.AutoAck, consumer: consumer);
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex, $"RabbitMQReceivedBinder.Received异常:", filename: $"RabbitMQReceivedBinder.Received_RabbitMQ_{queueName}_Exception");

                throw;
            }
        }