Очередь задач перед продакшеном: чек-лист проверки
Очередь, которая работает на тестовом стенде, может терять задачи, дублировать платежи и забирать весь ресурс базы под нагрузкой. Чек-лист помогает проверить надёжность, повторы, задержки, мониторинг и план восстановления до релиза.

Очередь задач редко ломается в момент отправки первого сообщения. Проблемы начинаются позже: воркер подтвердил задачу до записи результата, повторный запуск создал дубликат, а при остановке брокера система не смогла восстановить обработку. Этот чек-лист рассчитан на подготовку очередей к продакшену и применим к архитектурам на RabbitMQ 4.x и Apache Kafka 4.x; конкретные параметры нужно сверять с документацией установленной версии.
Сначала зафиксируйте контракт задачи
До настройки брокера опишите, что именно считается задачей. Название очереди или топика само по себе контрактом не является: обработчику нужны формат сообщения, правила повторов и понятный результат.
- Идентификатор: у каждой задачи есть уникальный ID, который сохраняется в логах и в хранилище результата.
- Тип и версия: например,
invoice.createdи версия схемы2. Не меняйте смысл старого поля без совместимости с уже опубликованными сообщениями. - Полезная нагрузка: передавайте идентификаторы и небольшие параметры, а не файл на десятки мегабайт или снимок всей записи из базы.
- Срок актуальности: уведомление о скидке и пересчёт баланса имеют разную цену задержки. Укажите, что делать с просроченной задачей.
- Результат: определите, где хранится успешный итог, ошибка и число попыток.
Схема сообщения должна быть доступна разработчикам и дежурной смене. Если формат хранится только в коде отправителя, первая миграция превращается в поиск по нескольким репозиториям.
Выберите модель доставки, а не только продукт
Главный вопрос — что произойдёт, если процесс упадёт после выполнения операции, но до подтверждения сообщения. В большинстве систем доставки нельзя одновременно получить строгую гарантию «ровно один раз» для внешнего побочного эффекта без дополнительных механизмов. Практический базовый вариант — доставка как минимум один раз и идемпотентный обработчик.
Идемпотентность[1] означает, что повторное выполнение одной и той же операции не меняет итог после первого успешного выполнения. Для этого обработчик может проверять уникальный ключ операции в базе, использовать уникальное ограничение или записывать статус обработки в одной транзакции с бизнес-изменением.
Если система не умеет безопасно пережить повтор задачи, проблема не в размере очереди. Она в отсутствии контракта между обработчиком и бизнес-операцией.
Что выбрать для разных задач
| Подход | Когда подходит | Цена решения | Что проверить |
|---|---|---|---|
| Брокер очередей, например RabbitMQ | Фоновые операции, маршрутизация, отдельное подтверждение каждой задачи | Нужно проектировать ack, повторы, dead-letter и число потребителей | Поведение при недоступности брокера, порядок подтверждения, лимит незавершённых сообщений |
| Журнал событий, например Kafka | Поток событий, несколько независимых потребителей, повторное чтение истории | Сложнее модель потребления и хранение истории; «задача» не исчезает после чтения | Группы потребителей, отставание, ключ партиционирования, срок хранения |
| Таблица задач в базе | Небольшой объём, когда важна транзакционная связь с бизнес-записью | Очередь конкурирует с приложением за ресурсы базы | Индексы, блокировки, очистка старых записей, план роста |
Не смешивайте эти модели в одном описании. В RabbitMQ подтверждение обычно означает, что потребитель закончил работу с сообщением. В Kafka смещение чтения и завершение бизнес-операции — разные события, поэтому позицию потребителя нельзя бездумно считать доказательством успеха.
Пройдите чек-лист надёжности
- Определите момент подтверждения. Сообщение нельзя подтверждать сразу после получения, если результат ещё не записан. Проверьте сценарий падения между внешним вызовом и ack: задача должна либо повториться безопасно, либо попасть в контролируемое состояние.
- Сделайте обработчик повторяемым. Передайте в него постоянный ID операции и добавьте защиту от повторов в том хранилище, где меняются бизнес-данные. Проверка считается пройденной, если два запуска с одинаковым ID дают один бизнес-результат.
- Разделите временные и постоянные ошибки. Сетевой таймаут или временная недоступность базы обычно допускают повтор. Ошибка схемы, отсутствие обязательной записи или отказ в правах требуют отдельного разбора и не должны бесконечно возвращаться в очередь.
- Настройте ограниченные повторы. Задайте число попыток, интервалы и верхнюю границу задержки. Быстрые повторы при падении внешнего сервиса создают лавину запросов; бесконечный retry скрывает неисправность.
- Выделите очередь неразобранных сообщений. Dead-letter queue, или DLQ, должна сохранять исходное сообщение, причину последнего отказа, время и число попыток. Проверьте, кто получает уведомление и как сообщение возвращается после исправления причины.
- Проверьте срок жизни. У задачи должен быть ответ на вопрос: имеет ли смысл выполнять её через час, день или неделю. Просроченные задания нужно отклонять, пересобирать или отправлять на ручной разбор.
- Ограничьте параллелизм. Число воркеров и одновременно выполняемых задач должно учитывать CPU, память, соединения с базой и лимиты внешнего API. Увеличение потребителей не ускорит систему, если узким местом остаётся база.
- Проверьте остановку. При деплое воркер должен перестать получать новые задачи, дождаться допустимого набора текущих операций и только затем завершиться. Отдельно протестируйте принудительное завершение процесса.
Проверьте нагрузку и обратное давление
Очередь не устраняет нехватку производительности, а превращает её в отложенную работу. Измеряйте не только количество сообщений, но и время ожидания до начала обработки, время выполнения, размер очереди, число повторов и долю ошибок.
Тест должен повторять продакшен-сценарий: тот же размер сообщения, похожие ответы внешних сервисов, реальный лимит базы и запланированное количество воркеров. Если таких замеров нет, не подставляйте выдуманный «безопасный» запас. Зафиксируйте методику: сколько сообщений отправлено, с какой скоростью, сколько обработано за интервал и какой процент завершился ошибкой.
Где подход ломается
- Очередь растёт, а CPU свободен. Ищите блокировку на базе, лимит соединений или медленный внешний API. Добавление воркеров может увеличить только количество таймаутов.
- Сообщения дублируются. Проверьте границу между бизнес-операцией и подтверждением, затем добавьте идемпотентный ключ. Не пытайтесь лечить дубли простым уменьшением числа потребителей.
- DLQ переполняется молча. Нужны метрики размера и скорости поступления, оповещение и понятный владелец разбора.
- После восстановления идёт шторм. Ограничьте скорость повторной обработки и заранее решите, какие старые задачи можно пропустить.
- Нарушается порядок. Если порядок важен только для одного объекта, привяжите последовательность к его ключу и проверьте, как масштабирование разделов или потребителей влияет на неё. Глобальный порядок резко ограничивает параллелизм.
Наблюдаемость и аварийные сценарии
Лог «сообщение получено» почти бесполезен без ID задачи, типа события, номера попытки, времени ожидания и результата. Не записывайте в логи токены, персональные данные и полный payload, если он не нужен для диагностики.
Минимальный набор сигналов:
- длина очереди или отставание потребителя;
- время от публикации до начала обработки;
- время выполнения и процент ошибок;
- число повторов и сообщений в DLQ;
- число активных воркеров и отказов подключения к брокеру;
- возраст самой старой необработанной задачи.
Для каждого сигнала задайте владельца и действие. Фраза «следить за очередью» не является runbook: дежурный должен знать, какие потребители остановить, где посмотреть причину и как не запустить повторную обработку вслепую.
Что проверить перед включением продакшена
Сделайте отдельный прогон с отказами, а не только успешный нагрузочный тест. Остановите воркер в середине задачи, отключите брокер на короткий интервал, заблокируйте внешний API, заполните DLQ тестовыми сообщениями и восстановите сервис. После каждого сценария сверяйте не только статус процесса, но и итоговые бизнес-данные.
Перед релизом полезно получить письменные ответы на семь вопросов:
- может ли одна задача выполниться дважды и безопасно ли это;
- где лежит уникальный ключ операции;
- сколько попыток разрешено и куда попадает последняя ошибка;
- кто разбирает DLQ и как выполняется повторный запуск;
- какой максимальный возраст задачи допустим;
- что происходит при остановке воркера и откате версии;
- какой показатель первым покажет, что система не справляется.
Что делать дальше
Сохраните контракт сообщения, таблицу отказов и runbook рядом с кодом сервиса. После релиза поставьте дашборд с возрастом самой старой задачи и временем ожидания: среднее значение может выглядеть нормально, пока небольшой процент сообщений застревает на часы. Следующий практический шаг — повторить тест с реальным размером очереди и проверить, что восстановление не создаёт дубликаты и не перегружает базу.
[1] Идемпотентность — свойство операции сохранять тот же итог при повторном выполнении с теми же входными данными.
Задачи: математика, физика, химия: Разбор задачи по шагам с проверкой и похожей задачей
Спросить за 10 ₽Источники: RabbitMQ Documentation: Consumer Acknowledgements and Publisher Confirms, Apache Kafka Documentation: Introduction
Частые вопросы
Можно ли гарантировать выполнение задачи ровно один раз?
Что выбрать для фоновых задач: RabbitMQ или Kafka?
Нужно ли делать отдельную очередь для ошибок?
Что делать, если очередь растёт, но воркеры работают?
Как проверить очередь перед релизом?
Что произойдёт с задачами при обновлении воркеров?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.