web-dev-qa-db-ja.com

pika(python)を使用してRabbitMQに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


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

エラーの説明:

トレースバック(最新の呼び出しは最後):
ファイル "C:\ work\projects\mq\start.py"、43行目、
のmethod_frame、header_frame、body = channel .basic_get(queue = "test_queue")
ファイル "C:\ work\projects\mq\libs\pika\adapters\blocking_connection.py"、318行目、basic_get 
 self.basic_get_( self、self._on_basic_get、ticket、queue、no_ack)
ファイル "C:\ work\projects\mq\libs\pika\channel.py"、行469、basic_get 
 no_ack = no_ack ))
ファイル「C:\ work\projects\mq\libs\pika\adapters\blocking_connection.py」、244行目、send_method 
 self.connection.process_data_events()
ファイル "C:\ work\projects\mq\libs\pika\adapters\blocking_connection.py"、94行目、process_data_events 
 self._handle_read()
内のファイル "C:\ work\projects\mq\libs\pika\adapters\base_connection.py "、行162、_handle_read 
 self._on_data_available(data)
ファイル" C:\ work\projects\mq\libs\pika\connection.py "、589行目、_on_data_availabl内e 
 frame)#Args 
 File "C:\ work\projects\mq\libs\pika\callback.py"、line 124、in process 
 callback(* args、 ** keywords)
ファイル "C:\ work\projects\mq\libs\pika\adapters\blocking_connection.py"、行269、_on_remote_close 
 frame.method.reply_text)
 AMQPChannelError:(406、 'PRECONDITION_FAILED-unknown delivery tag 204')

バージョン:pika 0.9.5、rabbitMQ 2.6.1

22
solo117

問題はおそらくno_ack=True このような:

consumer_tag = channel.basic_consume(
    message_delivery_event,
    no_ack=True,
    queue=queue,
)

次に、メッセージを確認します。

channel.basic_ack(delivery_tag=args.delivery_tag)

確認するかどうかを選択し、正しい消費パラメータを設定する必要があります。

44
Maiku Mori

私にとっては、確認するつもりはないとキューに言っただけで、確認しました。

例えば。 [〜#〜]間違った[〜#〜]

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 を参照)

12
David Beckwith

コードにバグがあります。スレッド間でチャネルを共有します。これはpikaではサポートされていません( [〜#〜] faq [〜#〜] を参照)。次の2つのオプションがあります。

  1. basic_get(...)で_no_ack=True_フラグを定義し、スレッドの関数doWork(...)でチャネルオブジェクトを使用しない
  2. 作業が終了した後でのみメッセージにACKを送信する必要がある場合は、メインスレッド(_while True:_ループ)がメッセージ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
    _
3
mike

修正方法はありませんが、BlockingConnectionアダプターを使用して問題が発生することを確認できます。

これは、channel.basic_recover()への応答として再配信されているメッセージを確認または拒否したときに常に発生します。

pika 0.9.5、rabbitMQ 2.2.0、python 2.7、およびErlang R14B01

私が実施している回避策は、常にdelivery_tag = 0を指定することです

これが機能するのは、確認/確認しているメッセージが最後に読んだ(ストリームで)メッセージである場合のみだと思います。私が書いているライブラリは、それぞれが個別に確認できるような方法でメッセージを抽象化しますが、これはこのソリューションではうまくいきません。

誰かがこれが修正されたか、pikaチームの誰かによってまだ承認されているかどうかを確認できますか?または、それはRabbitMQの問題でしょうか?

2

RabbitMQ-新しいバージョンにアップグレードし、「PRECONDITION_FAILED unknown delivery tag 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の問題である。

0

作成元の別のチャネルでメッセージを確認しようとした場合にも、このエラーが発生する可能性があります。これは、チャネルを閉じるか再作成する場合に発生する可能性があります。

ドキュメントから: https://www.rabbitmq.com/confirms.html

ブローカーが「不明な配信タグ」について不平を言うもう1つのシナリオは、配信が受信されたチャネルとは異なるチャネルで肯定応答または否定応答のいずれかが試行された場合です。配送は同じチャネルで確認する必要があります。

0
pfhayes

この問題は、{noack:true}を設定したにもかかわらず、確認応答を送信しようとしたために発生します。

0