我正在创建一个以无限循环运行的消费者来读取队列中的消息。我正在寻找关于如何在我的无限循环中继续恢复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;
}
答案 0 :(得分:16)
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客户端将恢复使用者并再次开始接收消息。
要进行更精细的控制,请为ConsumerCancelled
和Shutdown
连接事件处理程序以检测连接问题,并Registered
以了解何时可以再次使用该使用者。