如何在 RabbitMQ 中使用 py-amqplib 等待多个队列中的消息

120 阅读2分钟

在使用 py-amqplib 在 Python 中访问 RabbitMQ 时,应用程序会不时收到监听某些 MQ 主题的请求。它会在第一次收到请求时创建一个 AMQP 连接和一个信道,然后启动一个新线程来监听消息。

但是,在随后的订阅另一个主题的请求中,它会失败。在随后的请求中,我们重用了 AMQP 连接和 AMQPListener 线程(因为我们不想为每个主题启动一个新线程),而在调用上述代码块时,channel.queue_declare() 方法调用永远不会返回。

解决方案

我们可以通过在同一个信道中使用 basic_consume() 方法为每个队列附加一个消费者,然后使用 channel.wait() 方法来监听所有附加的队列。

以下是如何实现的代码示例:

connection = amqp.Connection(host = host, userid = "guest", password = "guest", virtual_host = "/", insist = False)
channel = connection.channel()

AMQPListener = threading.Thread
listener = AMQPListener(channel)
listener.start()

channel.queue_declare(queue = queueName, exclusive = False)
channel.exchange_declare(exchange = MQ_EXCHANGE_NAME, type = "direct", durable = False, auto_delete = True)
channel.queue_bind(queue = queueName, exchange = MQ_EXCHANGE_NAME, routing_key = destination)

def receive_callback(msg):
    self.queue.put(msg.body)

channel.basic_consume(queue = queueName, no_ack = True, callback = receive_callback)

def basic_consume(self, queue, consumer_tag, no_ack=False, exclusive=False, nowait=False, arguments=None, callback=None):
    """Consume messages from a queue.

    The consumer_tag is provided in the delivery headers of each received
    message.  It is recommended that the consumer tag be unique per channel,
    especially when using RabbitMQ’s high availability features.

    The consumer_tag can be made up of any printable ASCII character except
    the period character ('.'). The tag MUST NOT exceed 255 bytes. If an
    empty string is specified for the consumer tag it will be generated by
    the broker.

    Exclusive limits the consumer to this connection.

    See http://www.rabbitmq.com/amqp-0-9-1-reference.html#basic.consume

    Arguments:

    queue: The queue to consume from.
    consumer_tag: A label for the consumer. Used in the delivery headers.
    no_ack: If set, the broker will not wait for acknowledgements; this
    disables publisher acknowledgements for the channel. Note that
    reliable delivery of messages from the server cannot be guaranteed
    if acknowledgements are disabled.
    exclusive: If true, only this consumer can consume from the given queue.
    nowait: If set, the server will not respond to the exact request; instead,
        it will send a reply as soon as the request has been processed. The
        reply will be sent to the same channel from which the original request
        was sent. Responses to ``nowait`` methods will be returned in order.
    arguments: A table of arguments which the client may wish to pass to the
        server.  For example, this could contain fields like 'expiration'
        or 'max_length'.  This field is only supported for RabbitMQ 2.0 and
        higher.
    callback: A callback which will be invoked when messages are received.
        The callback takes two arguments:
            :param channel: The channel on which the message was received
            :type channel: amqp.channel.Channel
            :param basic_deliver: The basic.deliver message that was received
            :type basic_deliver: amqp.basic_deliver.BasicDeliver

    Returns:
        The consumer tag associated with the subscription.

    Raises:
        IOError: In the event that the method couldn’t be sent.
    """
    return self._consume(queue, consumer_tag, no_ack, exclusive, nowait, arguments, callback)

当要取消对某个队列的监听时,我们可以通过 channel.basic_cancel(consumer_tag) 方法来取消特定的消费者。