Rabbit MQ - 恢复连接/通道/消费者

时间:2015-11-13 18:06:46

标签: c# rabbitmq

我正在创建一个以无限循环运行的消费者来读取队列中的消息。我正在寻找关于如何在我的无限循环中继续恢复abd的建议/示例代码,即使存在网络中断。消费者必须保持运行,因为它将作为WindowsService安装。

1)有人可以解释如何正确使用这些设置吗?他们之间有什么区别?

NetworkRecoveryInterval 
AutomaticRecoveryEnabled
RequestedHeartbeat

2)请查看我当前的消费者示例代码。我使用的是.Net RabbitMQ Client v3.5.6。

以上设置如何为我“恢复”? 例如将consumer.Queue.Dequeue阻止,直到它被恢复? 这似乎不对 所以...

我是否需要手动编码?例如将consumer.Queue.Dequeue抛出一个异常,我必须检测并手动重新创建我的连接,通道和消费者?或者只是消费者,因为“AutomaticRecovery”会为我恢复频道吗?

这是否意味着我应该在while循环中移动使用者创建?那么频道创作呢?和连接创建?

3)假设我必须手动执行一些恢复代码,是否有事件回调(以及如何注册它们)告诉我存在网络问题?

谢谢!

public void StartConsumer(string queue)
{
            using (IModel channel = this.Connection.CreateModel())
            {
                var consumer = new QueueingBasicConsumer(channel);
                const bool noAck = false;
                channel.BasicConsume(queue, noAck, consumer);

                // do I need these conditions? or should I just do while(true)???
                while (channel.IsOpen &&        
                       Connection.IsOpen &&     
                       consumer.IsRunning)
                {
                    try
                    {
                        BasicDeliverEventArgs item;
                        if (consumer.Queue.Dequeue(Timeout, out item))
                        {
                            string message = System.Text.Encoding.UTF8.GetString(item.Body);
                            DoSomethingMethod(message);
                            channel.BasicAck(item.DeliveryTag, false);
                        }
                    }
                    catch (EndOfStreamException ex)
                    {   
                        // this is likely due to some connection issue -- what am I to do?
                    }
                    catch (Exception ex)
                    {   
                        // should never happen, but lets say my DoSomethingMethod(message); throws an exception
                        // presumably, I'll just log the error and keep on going
                    }
                }
            }
}

        public IConnection Connection
        {
            get
            {
                if (_connection == null) // _connection defined in class -- private static IConnection _connection;
                {
                     _connection = CreateConnection();
                }
                return _connection;
            }
        }

        private IConnection CreateConnection()
        {
            ConnectionFactory factory = new ConnectionFactory()
            {
                HostName = "RabbitMqHostName",
                UserName = "RabbitMqUserName",
                Password = "RabbitMqPassword",
            };

            // why do we need to set this explicitly? shouldn't this be the default?
            factory.AutomaticRecoveryEnabled = true;

            // what is a good value to use?
            factory.NetworkRecoveryInterval = TimeSpan.FromSeconds(5); 

            // what is a good value to use? How is this different from NetworkRecoveryInterval?
            factory.RequestedHeartbeat = 5; 

            IConnection connection = factory.CreateConnection();
            return connection;
        }

1 个答案:

答案 0 :(得分:16)

RabbitMq功能

documentation on RabbitMq's site实际上非常好。如果要恢复队列,交换和使用者,您需要查找拓扑恢复,默认情况下已启用。自动恢复(默认情况下未启用)包括:

  • 重新连接
  • 恢复连接侦听器
  • 重新开放频道
  • 恢复频道监听器
  • 恢复频道basic.qos设置,发布商确认和交易设置

NetworkRecoveryInterval是执行自动恢复重试之前的时间(默认为5秒)。

Heartbeat有另一个目的,即识别死TCP连接。在RabbitMq的网站上有more to read about that

代码示例

编写可靠的恢复代码非常棘手。 EndOfStreamException(正如您所怀疑的)最有可能是由于网络问题。如果使用management plugin,则可以通过从那里关闭连接来重现此操作,并查看是否触发了异常。对于类似生产的应用程序,您可能希望拥有一组代理,以便在连接失败时进行切换。如果您有几个RabbitMq代理,您可能还希望防范一台或多台服务器上的长期服务器故障。您可能希望实现错误策略,例如重新排队:消息或使用死信交换。

我一直在思考这些事情并编写了一个瘦客户端RawRabbit,它处理其中的一些事情。也许它可能适合你?如果没有,我建议您将QueueingBasicConsumer更改为EventingBasicConsumer。它是事件驱动的,而不是线程阻塞。

var eventConsumer = new EventingBasicConsumer(channel);
eventConsumer.Received += (sender, args) =>
{
    var body = args.Body;
    eventConsumer.Model.BasicAck(args.DeliveryTag, false);
};
channel.BasicConsume(queue, false, eventConsumer);

如果激活拓扑恢复,RabbitMq客户端将恢复使用者并再次开始接收消息。 要进行更精细的控制,请为ConsumerCancelledShutdown连接事件处理程序以检测连接问题,并Registered以了解何时可以再次使用该使用者。