Как устроена работа с RabbitMQ: отправитель, получатель, подписчики
Что проверяют
Различаете ли вы очередь задач и рассылку событий: в первом случае воркеры конкурируют, во втором каждый подписчик получает свою копию. Следом обычно спрашивают, как не потерять сообщение при падении воркера и чем pika неудобна в асинхронном коде.
Как отвечать
- отправитель: публикует в exchange, а не в очередь.
basic_publish(exchange='', routing_key='tasks')идёт через default exchange, который кладёт сообщение в очередь с таким именем; - получатель:
basic_consumeс колбэком, брокер сам доставляет сообщения. Воркеры на одной очереди делят поток, каждое сообщение уходит одному.basic_qos(prefetch_count=1)не даёт одному воркеру набрать пачку, пока другие простаивают; - подписчики: обменник
fanoutилиtopicи у каждого подписчика своя очередь. Временную объявляют какqueue_declare(queue='', exclusive=True): брокер даст ей имя и удалит при отключении. Затемqueue_bindс ключом, вtopicработают шаблоны*(одно слово) и#(сколько угодно слов); - надёжность:
durable=Trueу очереди,delivery_mode=2у сообщения,auto_ack=Falseиbasic_ack(delivery_tag=method.delivery_tag)в конце колбэка. На отправителе включаютchannel.confirm_delivery(), иначе вы не узнаете, что брокер сообщение не принял.
Python-специфика: BlockingConnection не потокобезопасен, одно соединение на поток. Колбэк, который работает дольше таймаута heartbeat, не даёт соединению отвечать брокеру, и тот закрывает соединение. Долгую работу выносят в отдельный поток, а ack возвращают через add_callback_threadsafe. В asyncio-сервисах берут aio-pika или FastStream, а для фоновых задач часто хватает Celery с RabbitMQ в роли брокера.
Где спотыкаются
Оставляют auto_ack=True, как в примере из туториала. Воркер упал посреди обработки, сообщение пропало.
Думают, что durable=True у очереди делает постоянными и сообщения. Без delivery_mode=2 они исчезнут при перезапуске брокера.
От переполнения советуют x-max-length и не знают, что лишние сообщения по умолчанию молча выбрасываются с головы очереди. Если терять нельзя, нужен x-overflow со значением reject-publish или dead letter exchange.