[英]Error “unknown delivery tag” occurs when i try ack messages to RabbitMQ using pika (python)
我想在几个线程中使用进程消息但是在执行此代码时我遇到错误:
from __future__ import with_statement
import pika
import sys
from pika.adapters.blocking_connection import BlockingConnection
from pika import connection, credentials
import time
import threading
import random
from pika.adapters.select_connection import SelectConnection
from pika.connection import Connection
import traceback
def doWork(body, args, channel):
r = random.random()
time.sleep(r * 10)
try:
channel.basic_ack(delivery_tag=args.delivery_tag)
except :
traceback.print_exc()
auth = credentials.PlainCredentials(username="guest", password="guest")
params = connection.ConnectionParameters(host="localhost", credentials=auth)
conn = BlockingConnection(params)
channel = conn.channel()
while True:
time.sleep(0.03)
try:
method_frame, header_frame, body = channel.basic_get(queue="test_queue")
if method_frame.NAME == 'Basic.GetEmpty':
continue
t = threading.Thread(target=doWork, args=[body, method_frame, channel])
t.setDaemon(True)
t.start()
except Exception, e:
traceback.print_exc()
continue
错误说明:
Traceback (most recent call last): File "C:\work\projects\mq\start.py", line 43, in method_frame, header_frame, body = channel.basic_get(queue="test_queue") File "C:\work\projects\mq\libs\pika\adapters\blocking_connection.py", line 318, in basic_get self.basic_get_(self, self._on_basic_get, ticket, queue, no_ack) File "C:\work\projects\mq\libs\pika\channel.py", line 469, in basic_get no_ack=no_ack)) File "C:\work\projects\mq\libs\pika\adapters\blocking_connection.py", line 244, in send_method self.connection.process_data_events() File "C:\work\projects\mq\libs\pika\adapters\blocking_connection.py", line 94, in process_data_events self._handle_read() File "C:\work\projects\mq\libs\pika\adapters\base_connection.py", line 162, in _handle_read self._on_data_available(data) File "C:\work\projects\mq\libs\pika\connection.py", line 589, in _on_data_available frame) # Args File "C:\work\projects\mq\libs\pika\callback.py", line 124, in process callback(*args, **keywords) File "C:\work\projects\mq\libs\pika\adapters\blocking_connection.py", line 269, in _on_remote_close frame.method.reply_text) AMQPChannelError: (406, 'PRECONDITION_FAILED - unknown delivery tag 204')
版本:pika 0.9.5,rabbitMQ 2.6.1
问题可能是你正在设置no_ack=True
如下所示:
consumer_tag = channel.basic_consume(
message_delivery_event,
no_ack=True,
queue=queue,
)
然后确认消息:
channel.basic_ack(delivery_tag=args.delivery_tag)
如果要确认或不确认,则必须选择并设置正确的消耗参数。
对我来说,只是我告诉队列我不打算,然后我说。
如错 :
channel.basic_consume(callback, queue=queue_name, no_ack=True)
然后在我的回调中:
def callback(ch, method, properties, body):
# do stuff
ch.basic_ack(delivery_tag = method.delivery_tag)
右 :
channel.basic_consume(callback, queue=queue_name, no_ack=False)
底线 :如果您想手动确认,请设置no_ack = False。
来自文档:
no_ack:(bool)如果设置为True,将使用自动确认模式(请参阅http://www.rabbitmq.com/confirms.html )
我没有修复,但我可以使用BlockingConnection适配器验证它是否发生。
当确认或拒绝响应channel.basic_recover()而重新传递的消息时,它始终发生
pika 0.9.5,rabbitMQ 2.2.0,python 2.7和Erlang R14B01
我所采用的解决方法是始终指定deliver_tag = 0
我怀疑这只有在你正在寻找的消息/ nacking是你读过的最后一个消息时才会有效(在流中)。 我正在编写的库以这样的方式抽象消息,即每个人都可以独立确认,这打破了这个解决方案。
任何人都可以确认这个已经被pika团队中的任何人修复或确认了吗? 或者,这可能是RabbitMQ的问题吗?
您的代码存在错误。 您跨线程共享一个通道。 pika不支持此功能(请参阅常见问题解答 )。 你有2个选择:
basic_get(...)
定义no_ack=True
标志,不要在线程函数doWork(...)
使用通道对象doWork(...)
如果只在完成工作后需要确认消息,那么让主线程( while True:
loop)处理消息ack(而不是工作线程)。 下面是您的代码的修改版本。
from __future__ import with_statement import pika import sys from pika.adapters.blocking_connection import BlockingConnection from pika import connection, credentials import time import threading import random from pika.adapters.select_connection import SelectConnection from pika.connection import Connection import traceback from Queue import Queue, Empty def doWork(body, args, channel, ack_queue): time.sleep(random.random()) ack_queue.put(args.delivery_tag) def doAck(channel): while True: try: r = ack_queue.get_nowait() except Empty: r = None if r is None: break try: channel.basic_ack(delivery_tag=r) except: traceback.print_exc() auth = credentials.PlainCredentials(username="guest", password="guest") params = connection.ConnectionParameters(host="localhost", credentials=auth) conn = BlockingConnection(params) channel = conn.channel() # Create a queue for the messages that should be ACKed by main thread ack_queue = Queue() while True: time.sleep(0.03) try: doAck(channel) method_frame, header_frame, body = channel.basic_get(queue="test_queue") if method_frame.NAME == 'Basic.GetEmpty': continue t = threading.Thread(target=doWork, args=[body, method_frame, channel, ack_queue]) t.setDaemon(True) t.start() except Exception, e: traceback.print_exc() continue
生成此问题的原因是您已设置{noack:true},但仍尝试发送确认。
如果您尝试在创建它的其他通道上确认消息,则可能还会遇到此错误。 如果要关闭或重新创建频道,可能会发生这种情况。
来自文档: https : //www.rabbitmq.com/confirms.html
经纪人将抱怨“未知交付标签”的另一种情况是,在与接收交付的渠道不同的渠道上尝试确认(无论是正面还是负面)。 交货必须在同一渠道上确认。
看到RabbitMQ后 - 升级到新版本并获得了很多“PRECONDITION_FAILED未知交付标签1”
我改变了我的基本消耗,看起来像这样:
consumer_tag = channel.basic_consume(
message_delivery_event,
no_ack=True,
queue=queue,
)
当指定消息的传递标记时,这会导致在初始(未重新传递)确认时引起所描述的错误。 传递是从消息传递的方法结构中提取的。
运用
channel.basic_ack(delivery_tag=0)
在这种情况下也会抑制错误
查看http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2011-July/013664.html使它看起来好像在RabbitMQ中可能是一个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.