Как обрабатываются ошибки в RabbitMQ?
Что проверяют
Понимаете ли вы, где в цепочке «продюсер, брокер, консьюмер» теряются сообщения и чем закрывается каждый участок. Следом почти всегда спрашивают про «ядовитое» сообщение, которое раз за разом роняет обработчик.
Как отвечать
Публикация:
- publisher confirms: брокер подтверждает приём. В pika это
channel.confirm_delivery(), в aio-pika подтверждения на канале включены по умолчанию; mandatory=True: сообщение, не попавшее ни в одну очередь, вернётся продюсеру, а не исчезнет молча;- долговечность: durable-очередь и
delivery_mode=2. Реплицируемые очереди сейчас это quorum queues, зеркалирование классических убрано в RabbitMQ 4.0.
Обработка:
- ручные подтверждения:
auto_ack=False, после успехаbasic_ack. Упал консьюмер до ack, и сообщение вернётся в очередь с флагомredelivered; - отказ:
basic_nack(requeue=False)илиbasic_rejectпри неисправимой ошибке. В aio-pika то же делаетasync with message.process()при исключении; - dead letter exchange: аргумент
x-dead-letter-exchangeнаправляет туда отклонённые, просроченные по TTL и вытесненные по лимиту длины сообщения; - повторы с задержкой: очередь с
x-message-ttl, чей DLX указывает обратно на рабочую. У quorum queues естьx-delivery-limit, после него сообщение уходит в DLX; basic_qos(prefetch_count=N): сколько неподтверждённых сообщений держит один консьюмер.
Итог: гарантия получается «хотя бы один раз», поэтому обработчик обязан быть идемпотентным.
Где спотыкаются
Оставляют auto_ack=True. Сообщение считается доставленным в момент отправки, и падение обработчика его теряет.
Делают nack с requeue=True на любую ошибку. Сообщение с битыми данными возвращается в очередь и крутится бесконечно, съедая CPU.
Выполняют долгую синхронную работу в колбэке BlockingConnection pika. Heartbeat не уходит, брокер рвёт соединение, сообщение приходит повторно, и без идемпотентности вы получаете дубли.