在使用 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) 方法来取消特定的消费者。