amqplib - 尽管调用了channel.ack(msg),但消息仍然没有被删除

时间:2014-02-03 12:05:17

标签: node.js rabbitmq amqp

我正在编写一个模块,它充当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

1 个答案:

答案 0 :(得分:5)

为了完整,用我发现的东西回答我自己的问题。这实际上取决于node-amqpamqp.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;

};

值得注意的是,如果有人遇到类似的情况。