我有一个Windows服务,它使用来自远程托管的RabbitMQ队列的消息。
我有工作代码,它以固定的时间间隔唤醒并连接到队列并接收消息并处理它们(大多数将它们保存到数据库中)。这是对我有用的简化版本:
#region currentmethod
IConnection connection = factory.CreateConnection();
IModel channel = connection.CreateModel();
channel.ExchangeDeclare(EXCHANGE_NAME, ExchangeType.Direct, true, false, null);
QueueDeclareOk queueDeclareOK = channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: true, arguments: null);
channel.QueueBind(queue: queueName, exchange: EXCHANGE_NAME, routingKey: routingkey);
Console.WriteLine(queueDeclareOK.MessageCount.ToString());
BasicGetResult result = channel.BasicGet(queueName, false);
byte[] body = result.Body;
string message = Encoding.UTF8.GetString(body);
if (ProcessData(message))
channel.BasicAck(result.DeliveryTag, false);
else
channel.BasicNack(result.DeliveryTag, false, true);
channel.Close(200, "goodbye");
connection.Close();
#endregion currentmethod
我想要做的是实现https://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html所述的发布 - 订阅模型,以便当消息进入队列时,订阅者立即处理它们。我需要确保的是,如果消息未成功处理,它将保留在队列中并且不会丢失。
以下是基本上这些代码的代码:
#region subscribeModel
using (connection = factory.CreateConnection())
{
using (channel = connection.CreateModel())
{
channel.ExchangeDeclare(EXCHANGE_NAME, ExchangeType.Direct, true, false, null);
channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: true, arguments: null);
channel.QueueBind(queueName, EXCHANGE_NAME, routingKey);
EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
consumer.Received += (o, e) =>
{
string data = Encoding.ASCII.GetString(e.Body);
Console.WriteLine(data);
};
string consumerTag = channel.BasicConsume(queueName, false, consumer);
Console.WriteLine("Listening, press ENTER to quit");
Console.ReadLine();
}
}
#endregion subscribeModel
我有三个困难。
读取消息后,它们处于Unacked状态,但我需要它们返回Ready状态。如果它们被成功处理,它们应该是Acked并离开队列,但如果处理失败,它们必须保留在队列中。
我需要做一些事情而不是将数据写入控制台,但是我将Process代码放在这个模型中的哪个位置?
当我的代码在订阅模型中终止时,我连接的队列将被删除,丢失任何状态下的任何消息。
有人知道如何重新排队未处理的邮件,并防止在我的消费者关闭时删除队列吗?
答案 0 :(得分:1)
我在上周没有机会看到这么多,但今天做了更多的研究,我想我现在可以回答我自己的问题,希望在此过程中帮助其他人。
肯定的确认只是指示RabbitMQ记录一条消息 交付。 basic.reject的否定确认有 同样的效果。差异主要在于语义:积极 确认假设消息已成功处理 他们的负面对应物表明交付没有得到处理 但仍应删除。
我可以通过将有缺陷的消息发送到新队列来实现我需要做的事情,在那里可以对它们进行不同的处理以解决使它们有缺陷的任何问题,如下所示:
using (channel)
{
EventingBasicConsumer consumer = new EventingBasicConsumer(channel);
consumer.Received += (o, e) =>
{
string data = Encoding.ASCII.GetString(e.Body);
result = MQ.utilities.Utilities.ProcessData(data, counter);
if (result)
channel.BasicAck(e.DeliveryTag, false);
else
{
channel.BasicNack(e.DeliveryTag, false, false);
//send message to another queue ...
IBasicProperties basicProperties = channel.CreateBasicProperties();
channel.BasicPublish(_exchangeName, "newqueue", basicProperties, e.Body);
}
};
string consumerTag = channel.BasicConsume(_publishSubscribeQueueOne, false, consumer);
Console.WriteLine("Listening, press ENTER to quit");
Console.ReadLine();
}
可以在消费者中收到的事件上发生procesdata方法。
这是因为队列被声明为autodelete。如果未设置为自动解除队列,则当消费者终止时,未打包的消息将返回到Ready状态。