Что такое гарантия доставки у брокера сообщений?

«Что такое гарантия доставки у брокера сообщений?» — вопрос из категории Брокеры сообщений, который задают на 24% собеседований AQA / Automation. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Гарантия доставки — это свойство системы обмена сообщениями, при котором брокер (например, RabbitMQ, Apache Kafka) обеспечивает, что отправленное сообщение будет обработано потребителем как минимум один раз, даже в случае сбоев на стороне брокера, отправителя или получателя.

С точки зрения тестирования, важно понимать и проверять эти механизмы:

Ключевые механизмы гарантии доставки:

  1. Подтверждение (Acknowledgement): Потребитель должен явно подтвердить (ack) успешную обработку сообщения. Без подтверждения брокер считает сообщение не доставленным и может перенаправить его другому потребителю.
  2. Сохранение на диск (Persistence): Сообщения и метаданные очередей сохраняются на диск, чтобы пережить перезапуск брокера.
  3. Репликация и кворумы: В кластерных конфигурациях (Kafka, RabbitMQ Quorum Queues) сообщения реплицируются на несколько узлов для отказоустойчивости.

Пример тестового сценария для RabbitMQ:

import pika
# Подключение к брокеру
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost'))
channel = connection.channel()
# Объявление устойчивой (durable) очереди
channel.queue_declare(queue='test_payment_queue', durable=True)

# Публикация сообщения в persistent-режиме
channel.basic_publish(
    exchange='',
    routing_key='test_payment_queue',
    body='Test payment data',
    properties=pika.BasicProperties(
        delivery_mode=2,  # Делает сообщение persistent
    )
)
print(" [x] Sent 'Test payment data'")

# --- Сторона потребителя (тестового сервиса) ---
def callback(ch, method, properties, body):
    print(f" [x] Received {body}")
    # Имитация обработки и проверки данных
    if process_payment(body):
        # Явное подтверждение ТОЛЬКО после успешной обработки
        ch.basic_ack(delivery_tag=method.delivery_tag)
    else:
        # Отказ от подтверждения. Сообщение будет повторно доставлено или попадет в DLQ
        ch.basic_nack(delivery_tag=method.delivery_tag)

# Подписка с отключенным auto_ack
channel.basic_consume(queue='test_payment_queue', on_message_callback=callback, auto_ack=False)
channel.start_consuming()

При тестировании мы специально эмулируем сбои (убиваем процесс потребителя) и проверяем, что сообщения не теряются и обрабатываются повторно, а также отслеживаем появление сообщений в Dead Letter Queue при многократных неудачах.