amqp-node / amqplib

AMQP 0-9-1 library and client for Node.JS

Home Page:https://amqp-node.github.io/amqplib/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

global prefetch become 0 if per-consume prefetch set

soryy708 opened this issue · comments

With the following environment:

  • RabbitMQ 3.10.2
  • Erlang 24.3.4
  • (Docker image: rabbitmq:3.10.2-management)

Run this MCVE:

import * as amqp from "amqplib";

(async () => {
  const connection = await amqp.connect({
    protocol: "amqp",
    hostname: "localhost",
    port: 5672,
    username: "...", // set this
    password: "...", // set this
  });
  const channel = await connection.createChannel();
  channel.prefetch(42, true);
  const { queue } = await channel.assertQueue("", { autoDelete: true });
  channel.prefetch(100, false);
  channel.consume(queue, () => null, { noAck: true });
})();

While this is running, go to RabbitMQ management plugin UI and look at this channel:

image

Expected:

We should see prefetch=100 for the consume, and global prefetch=42.

Actual:

Here we see the consume has prefetch=100 (as expected), but the global prefetch is 0 (but we expected what we have previously set it to 42).

If we comment out the per-consume prefetch like so:

import * as amqp from "amqplib";

(async () => {
  const connection = await amqp.connect({
    protocol: "amqp",
    hostname: "localhost",
    port: 5672,
    username: "balanceAdmin",
    password: "Aa123456",
  });
  const channel = await connection.createChannel();
  channel.prefetch(42, true);
  const { queue } = await channel.assertQueue("", { autoDelete: true });
  // channel.prefetch(100, false);
  channel.consume(queue, () => null, { noAck: true });
})();

then global prefetch is set to 42 as expected:

image

but per-consume prefetch is 0.

Hi @soryy708

I've run your code through WireShark and see the following

  channel.prefetch(42, true);
Advanced Message Queueing Protocol
    Type: Method (1)
    Channel: 1
    Length: 11
    Class: Basic (60)
    Method: Qos (10)
    Arguments
        Prefetch-Size: 0
        Prefetch-Count: 42
        .... ...1 = Global: True
channel.prefetch(100, false);
Advanced Message Queueing Protocol
    Type: Method (1)
    Channel: 1
    Length: 11
    Class: Basic (60)
    Method: Qos (10)
    Arguments
        Prefetch-Size: 0
        Prefetch-Count: 100
        .... ...0 = Global: False

So it looks like amqplib is sending the correct commands and arguments to the broker.

My best guess for what you're seeing in the management UI is that the channel's "prefetch count" and "global prefetch count" are the values that will be applied to subsequent consumer(s) created using this channel. Even if true, this is still misleading though since the RabbitMQ documentation states when both per-channel (global = true) and per-consumer (global = false) are set, both values are honoured.

The AMQP 0-9-1 specification does not explain what happens if you invoke basic.qos multiple times with different global values. RabbitMQ interprets this as meaning that the two prefetch limits should be enforced independently of each other; consumers will only receive new messages when neither limit on unacknowledged messages has been reached.

I think this one is for the RabbitMQ team / community.