Error “unknown delivery tag” occurs when i try ack messages to RabbitMQ using pika (python)

前端 未结 7 1045
别跟我提以往
别跟我提以往 2021-02-07 00:57

I want process messages in few threads but i\'m getting error during execute this code:

from __future__ import with_statement
import pika
import sys
from pika.ad         


        
相关标签:
7条回答
  • 2021-02-07 00:58

    This issue is generated because you have set the { noack: true }, but still trying to send acknowledgement.

    0 讨论(0)
  • 2021-02-07 01:01

    For me, it was just that I told the queue I wasn't going to ack, then I acked.

    E.g. WRONG:

    channel.basic_consume(callback, queue=queue_name, no_ack=True)
    

    and then in my callback:

    def callback(ch, method, properties, body):
      # do stuff
      ch.basic_ack(delivery_tag = method.delivery_tag)
    

    RIGHT:

    channel.basic_consume(callback, queue=queue_name, no_ack=False)
    

    Bottom line: If you want to manually ack, set no_ack=False.

    From the docs:

    no_ack: (bool) if set to True, automatic acknowledgement mode will be used (see http://www.rabbitmq.com/confirms.html)

    0 讨论(0)
  • 2021-02-07 01:03

    After seeing RabbitMQ - upgraded to a new version and got a lot of "PRECONDITION_FAILED unknown delivery tag 1"

    I changed my basic-consume to look like this:

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

    This had the effect of causing the described error on initial (not redelivered) acknowledgements when the message's delivery tag was specified. The delivery was extracted from the message delivery's method structure.

    Using

        channel.basic_ack(delivery_tag=0)
    

    suppresses the error in this case, too

    Looking at http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2011-July/013664.html makes it seem as though it may be an issue in RabbitMQ.

    0 讨论(0)
  • 2021-02-07 01:06

    The problem probably is that you're setting no_ack=True like this:

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

    And then acknowledging the messages:

    channel.basic_ack(delivery_tag=args.delivery_tag)
    

    You have to chose if you want to acknowledge or not and set the correct consume parameter.

    0 讨论(0)
  • 2021-02-07 01:09

    There is a bug with your code. You share a channel across threads. This is not supported by pika (see FAQ). You have 2 options:

    1. Define the no_ack=True flag in basic_get(...) and do not use the channel object in thread's function doWork(...)
    2. If you need to ACK message only after you have finished your work, then let the main thread (the while True: loop) handle the message ack (and not the worker thread). Below is a modified version of your code that does that.

      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
      
    0 讨论(0)
  • 2021-02-07 01:16

    You might also be encountering this error if you are trying to acknowledge a message on a different channel from which it was created. This might happen if you are closing or recreating channels.

    From the docs: https://www.rabbitmq.com/confirms.html

    Another scenario in which the broker will complain about an "unknown delivery tag" is when an acknowledgement, whether positive or negative, is attempted on a channel different from that on which the delivery was received on. Deliveries must be acknowledged on the same channel.

    0 讨论(0)
提交回复
热议问题