我正在编写一个模块,它充当amqplib的包装器。动机是,我们已经建立了一个现有的,定义良好的交换/队列/绑定,我只想公开使用消费方法以允许消费传入数据。
为此,我的模块采用callback(channel, msg)
形式的回调参数。在模块中,在设置了交换和队列以及绑定之后,我有以下
module.exports = function (options, callback) {
/* connection, exchange and queue set up here */
// consume messages from primary queue
ok = ok.then(function() {
var q = opts.pq;
console.log('Subscribing to', q);
return ch.consume(q, function (message) {
callback(ch, message);
});
});
return ok;
};
在回调中,我正在处理消息,并在成功时调用channel.ack(msg)
。
一切运行正常,因为没有错误,但是RabbitMQ管理控制台将所有已处理的消息显示为Unacked。如果我然后杀了我的应用程序,Unacked消息将返回队列(谢天谢地)。
为什么我的邮件没有被删除?我在ack'ing做错了吗?我是否应该在调用allUpTo
时将ack
参数设为true?
Env详情
node -v
v0.8.26
npm ls
...
amqplib@0.1.1
答案 0 :(得分:5)
为了完整,用我发现的东西回答我自己的问题。这实际上取决于node-amqp和amqp.node之间默认设置的差异以及我的消费者中的一个稍微有缺陷的实现。
订阅队列时,node-amqp默认使用prefetch=1
,这意味着任何时候只有1条消息在传输中。另一个将在上一次被确认之前交付。但是,amqp.node默认为prefetch=0
,这意味着所有消息都会尽快发送给消费者,并且当消费者完成每个消息时,可以在将来的某个时间单独确认消息。< / p>
这是我在管理控制台中看到的,它引起了警报并导致了这个问题。可以在this github issue中看到对此的讨论。
ASIDE - 根据上述信息,我让我的消费者继续运行,让它在准备就绪时发出消息。这为我的实现提出了一个单独的问题。考虑到我们正在传递的消息(即一次性传递)的方式,消息处理程序正在用新连接请求轰炸数据库。结果,数据库服务器过载,最终消费者死亡。为了解决这个问题,我刚才切换到prefetch=1
,这意味着上面的消费承诺方法现在如下:
module.exports = function (options, callback) {
/* connection, exchange and queue set up here */
// consume messages from primary queue
ok = ok.then(function() {
var q = opts.pq;
console.log('Subscribing to', q);
ch.prefetch(1); // <-- only get 1 message at a time
return ch.consume(q, function (message) {
callback(ch, message);
}, { noAck: false });
});
return ok;
};
值得注意的是,如果有人遇到类似的情况。