我正在尝试创建一个订阅多个队列的消费者,然后在消息到达时处理它们。
问题在于,当第一个队列中已经存在某些数据时,它会占用第一个队列,并且永远不会消耗第二个队列。 但是,当第一个队列为空时,它会转到下一个队列,然后同时消耗这两个队列。
我首先实现了线程,但是想要避开它,当pika库为我做的时候没有太多的复杂性。以下是我的代码:
import pika
mq_connection = pika.BlockingConnection(pika.ConnectionParameters('x.x.x.x'))
mq_channel = mq_connection.channel()
mq_channel.basic_qos(prefetch_count=1)
def callback(ch, method, properties, body):
print body
mq_channel.basic_ack(delivery_tag=method.delivery_tag)
mq_channel.basic_consume(callback, queue='queue1', consumer_tag="ctag1.0")
mq_channel.basic_consume(callback, queue='queue2', consumer_tag="ctag2.0")
mq_channel.start_consuming()
答案 0 :(得分:14)
一种可能的解决方案是使用非阻塞连接并使用消息。
import pika
def callback(channel, method, properties, body):
print(body)
channel.basic_ack(delivery_tag=method.delivery_tag)
def on_open(connection):
connection.channel(on_channel_open)
def on_channel_open(channel):
channel.basic_consume(callback, queue='queue1')
channel.basic_consume(callback, queue='queue2')
parameters = pika.URLParameters('amqp://guest:guest@localhost:5672/%2F')
connection = pika.SelectConnection(parameters=parameters,
on_open_callback=on_open)
try:
connection.ioloop.start()
except KeyboardInterrupt:
connection.close()
这将连接到多个队列,并相应地使用消息。
答案 1 :(得分:2)
问题很可能是第一次调用已发出Basic.Consume,并且在发出第二次调用之前已经从预先填充的队列中接收到消息。您可能想尝试将QoS预取计数设置为1,这将限制RabbitMQ一次向您发送多条消息。
答案 2 :(得分:0)
类似于上面第一个答案中的评论,我能够使用 pika 1.1.0 和以下版本获得类似的结果:
import pika
def queue1_callback(ch, method, properties, body):
print(" [x] Received queue 1: %r" % body)
def queue2_callback(ch, method, properties, body):
print(" [x] Received queue 2: %r" % body)
def on_open(connection):
connection.channel(on_open_callback = on_channel_open)
def on_channel_open(channel):
channel.basic_consume('queue1', queue1_callback, auto_ack = True)
channel.basic_consume('queue2', queue2_callback, auto_ack = True)
credentials = pika.PlainCredentials('u', 'p')
parameters = pika.ConnectionParameters('localhost', 5672, '/', credentials)
connection = pika.SelectConnection(parameters = parameters, on_open_callback = on_open)
Try:
connection.ioloop.start()
except KeyboardInterrupt:
connection.close()
connection.ioloop.start()
答案 3 :(得分:-1)
值得注意的是,上述解决方案仅在 auto_ack 设置为 True 时才有效。