[Python] RabbitMQ - Consume a Large Volume of Messages from a Queue withou ACK

Discussão em 'Python' iniciado por Stack, Julho 25, 2025.

  1. Stack

    Stack Membro Participativo

    I would like to read a large volume of messages from a RabbitMQ queue, but negatively acknowledge (NACK) them. Some other consumer will ACK them and do work later.

    I have 100,000 messages in a queue. The following Python code is my attempt to print information about all messages:

    # Script settings
    seen_message_ids = set()
    retrieved_number = 0
    delete_all_messages = False
    ids_to_delete = ['da140a51-cdd9-f71d-ac5c-ec15766e6aa4']

    def on_message(ch, method_frame, header_frame, body):
    # If all arguments other than `ch` are None, then the `consume` method timed out due to queue inactivity.
    # Stop listening to the queue.
    if method_frame is None and header_frame is None and body is None:
    ch.stop_consuming()
    return

    # Messages that are not deleted are re-queued, meaning they will be consumed again, infinitely. Keep track
    # of `message_id`, which is a UUID to identify message that were already seen. Since this is a FIFO queue,
    # seeing any message again means all messages in the queue have been examined.
    message_id = header_frame.message_id
    if message_id in seen_message_ids:
    print("All messages evaluated.")
    ch.stop_consuming()
    return
    seen_message_ids.add(message_id)

    # Keep track of the number of retrieved messages.
    global retrieved_number
    retrieved_number += 1

    # To keep the message, negatively acknowledge it and re-queue it.
    ch.basic_nack(delivery_tag=method_frame.delivery_tag, requeue=True)
    status = "READ "
    print(f"{status} {retrieved_number:06d} Message: {body.decode()} UUID: {header_frame.message_id}")
    return


    def main():
    connection = pika.BlockingConnection(
    pika.ConnectionParameters(host=RABBITMQ_HOST,
    port=RABBITMQ_PORT,
    virtual_host=RABBITMQ_VHOST,
    credentials=credentials))
    channel = connection.channel()
    channel.queue_declare(queue='test1')

    # Consume messages and acknowledge them
    print("START LISTENING")
    last_message_received_time = datetime.datetime.now()
    for method_frame, properties, body in channel.consume('test1', inactivity_timeout=1):

    # `consume` is a generator https://pika.readthedocs.io/en/stable/examples/blocking_consumer_generator.html
    # That means that the body of this for loop will not be reached unless a new message is found.
    new_message_received_time = datetime.datetime.now()
    if method_frame is None and properties is None and body is None:
    print(f"Timeout due to inactivity after {new_message_received_time - last_message_received_time} elapsed.")
    on_message(channel, method_frame, properties, body)

    try:
    channel.start_consuming()
    except KeyboardInterrupt:
    channel.stop_consuming()
    finally:
    print("STOP LISTENING")
    connection.close()


    This approach succeeds until about 5,000 messages have been retrieved. Then this happens:

    • The ~5,000th message is printed: READ 005112 Message: {"job_id": "AAAAAAAAAAAAA"} UUID: 86d26605-33d6-9c61-68f8-a67abdf76a13
    • This message is printed: All messages evaluated. For this condition to be met, the script must have encountered a previously sent message_id, which is a Guid. Since the guids are distinct, the only way to see a repeated guid is for a re-queued message to be retrieved again. Shouldn't re-queued messages go to the back of the queue, though? I expected to see re-queued messages only after the 100,000 messages already in the queue were retrieved.
    • The RabbitMQ management UI shows most messages as Unacked. The number of unacked messages goes to zero over several minutes, or sometimes a few seconds.

    [​IMG]

    • The consumer remains stuck on ch.stop_consuming(), which is immediately after All messages evaluated until the management UI shows all messages as Ready.
    • An attempt to retrieve messages using a second consumer fails to find any.
    • An attempt to retrieve messages using the management UI fails to find any.

    Why does the consumer not receive and print all 100,000 messages? What work-arounds are available?

    Someone will probably ask why I want to read an NACK all messages. In fact, I want to ACK one or a few as a way to remove it from the queue. However, I can't ACK a message if my consumer never retrieves it. References to this approach for removing a message are here: SO1 and here: SO2

    Continue reading...

Compartilhe esta Página