Webhook упал по таймауту. Тяжёлая обработка заблокировала весь процесс. Пользователь видел пустой экран три минуты, а потом получил ошибку 500.
Это не сбой — это архитектурная проблема. Приём события и его обработка сидят в одном процессе, хотя у них совершенно разные требования к времени и надёжности. Принять нужно мгновенно. Обработать можно потом.
Очереди и фоновые задачи — это паттерн, который разделяет эти две ответственности. Событие попадает в буфер, а отдельный воркер обрабатывает его в своём темпе, с повторами при сбоях. В этом материале разберём, как это устроено, какие инструменты выбрать и где обычно ошибаются.
Что это
Очередь — буфер между появлением задачи и её выполнением. Кто-то кладёт задачу в буфер, кто-то другой забирает и обрабатывает. Если обработка ломается, задача не исчезает — она ждёт повторной попытки.
Представьте ресторан: официант принимает заказ и передаёт его на кухню через конвейер. Повар берёт заказы по очереди — не одновременно, не хаотично. Если блюдо сгорело, заказ возвращается в очередь и готовится заново. Официант не стоит у плиты — он уже ушёл к следующему столу.
В программной архитектуре это работает так: событие (webhook, клик, триггер от внешнего сервиса) попадает в очередь. Отдельный процесс — воркер — опрашивает очередь и берёт задачи одну за другой. Успешно обработал — задача удаляется. Не вышло — возвращается в очередь для повтора.
flowchart LR
A["Событие"] --> B["Буфер"]
B --> C["Воркер"]
C --> D["Результат"]
C -->|"Сбой"| E["Backoff"]
E --> B
Зачем нужны очереди
Надёжность
Без очереди сбой означает потерю. Обработчик упал посреди генерации отчёта — отчёта больше нет. С очередью задача остаётся в буфере: воркер перезапустится, заберёт её снова и доведёт до конца. Для платежей, уведомлений и документов это разница между «повторим» и «потеряли навсегда».
Скорость ответа
Внешние системы ждут ответа 5–30 секунд — потом обрывают соединение. Если обработка занимает минуты (генерация черновика, рассылка, анализ), синхронный ответ неизбежно таймаутит. Очередь разрывает эту связку: webhook кладёт задачу и мгновенно возвращает 200 OK. Обработка идёт в фоне.
Масштабирование
Поток задач неравномерный. Днём — пик, ночью — простой. Один воркер захлёбывается — добавьте второй, третий, десятый. Брокер распределит нагрузку равномерно. Это горизонтальное масштабирование без переписывания архитектуры.
Порядок и предсказуемость
FIFO (First In, First Out) гарантирует: кто первым пришёл, первым обработан. Для финансовых транзакций и последовательных обновлений это критично — без очереди порядок зависит от скорости сети и удачи.
Как устроено
Архитектура очереди — три слоя:
- Продюсер — тот, кто кладёт задачу. Webhook-обработчик, пользовательское действие, триггер от n8n или Make.
- Брокер — хранилище очереди. Redis, RabbitMQ, PostgreSQL — что-то, что переживает рестарт.
- Воркер (консьюмер) — процесс, который забирает задачи и выполняет их.
Воркер должен быть идемпотентным: повторное выполнение той же задачи не ломает данные. Это обязательно, потому что при сбое задача выполняется частично, а потом повторяется с начала. Идемпотентность гарантирует, что повтор безопасен.
Если задача не выполняется после N попыток, она попадает в dead-letter queue (DLQ) — отдельный буфер для «мёртвых» задач. Это не даёт очереди зациклиться на одной ошибке и позволяет разобраться потом: что пошло не так, какие данные привели к сбою.
Когда использовать
Очередь — не панацея. Если обработка занимает миллисекунды и потеря задачи некритична, синхронный вызов проще и дешевле. Но при любом из этих условий очередь становится необходимостью:
- Обработка дольше нескольких секунд — webhook таймаутит, пользователь ждёт
- Потеря задачи недопустима — платежи, уведомления, документы
- Нагрузка неравномерная — пик превышает возможности одного процесса
- Порядок важен — FIFO гарантирует последовательность
- Нужны автоматические retry с backoff при ошибках
Пример: четыре сценария
Сравним, как одна и та же задача ведёт себя с очередью и без:
| Сценарий | Синхронно (без очереди) | Через очередь |
|---|---|---|
| Webhook от Notion | Агент обрабатывает сразу, риск таймаута 504 | Webhook кладёт задачу, воркер обрабатывает в фоне |
| Отправка email | Пользователь ждёт ответа, пока SMTP отвечает | Пользователь видит результат, письмо уходит фоном |
| Генерация черновика | Процесс заблокирован на 2–5 минут | Задача в очереди, агент свободен для других запросов |
| Обработка оплаты | Сбой midway — данные в неконсистентном состоянии | Сбой — задача возвращается в очередь, повторяется целиком |
Общий принцип: разделить «принять» и «обработать». Принять нужно быстро. Обработать можно долго.
Инструменты
Выбор зависит от стека, сложности сценария и готовности поддерживать инфраструктуру:
- Redis + BullMQ — связка для Node.js-проектов. BullMQ — это библиотека очередей поверх Redis. Поддерживает FIFO и LIFO, приоритеты задач, отложенный запуск, повторы с экспоненциальным backoff, параллельную обработку несколькими воркерами и восстановление состояния после падения процесса.
- RabbitMQ — полноценный брокер сообщений. Поддерживает маршрутизацию по подпискам, очереди с приоритетами, dead-letter exchanges, подтверждение доставки. Тяжелее в настройке, чем Redis, но даёт точный контроль над потоком сообщений и подходит для микросервисных архитектур.
- n8n / Make — low-code платформы автоматизации. Очереди встроены в платформу: не нужно разворачивать Redis или RabbitMQ отдельно. Достаточно настроить workflow — платформа сама управляет порядком выполнения и retry.
- Supabase Edge Functions — serverless-функции с очередями через PostgreSQL. Подходят, если Supabase уже используется как основная база данных и добавлять Redis нет смысла.
Для простых случаев очередь можно собрать даже в Notion: база данных со статусами «Новый» → «В обработке» → «Готово». Это та же очередь — без автоматических retry и с ручным управлением, но концептуально эквивалентная.
Ограничения
Ограничения
Что учитывать при внедрении:
Сложность инфраструктуры — Redis и RabbitMQ — это отдельные сервисы.
Их нужно разворачивать, мониторить, бэкапить. Для простых проектов это избыточно.
Идемпотентность обязательна — воркер должен безопасно переживать повторное выполнение.
Без этого retry-механизм сломает данные: двойные платежи, дубликаты записей, неконсистентное состояние.
Порядок при параллельности — несколько воркеров нарушают строгий FIFO.
Если порядок критичен, нужен один воркер или отдельная очередь с гарантией порядка.
Dead-letter queue требует ручного разбора — задачи в DLQ не исчезают.
Их нужно разбирать вручную или через отдельный процесс, иначе буфер растёт бесконечно.
Антипаттерны
Антипаттерны
Чего не делать:
Тяжёлая работа в webhook — не обрабатывать данные прямо в обработчике webhook.
Webhook должен принять задачу, положить в очередь и вернуть 200 OK за секунды.
Retry без backoff — не повторять задачу мгновенно при каждой ошибке.
Экспоненциальный backoff: первая попытка через секунду, вторая через две, третья через четыре. Иначе лавина запросов добьёт и очередь, и внешний сервис.
Нет мониторинга — если задачи копятся, а алерта нет, вы узнаете о проблеме от пользователей.
Мониторинг длины очереди — обязателен.
Один воркер для всего — разные типы задач (email, генерация, обработка файлов) лучше развести по отдельным очередям с независимыми воркерами.
Иначе медленная задача заблокирует быстрые.
In-memory очередь в продакшене — при рестарте сервера все задачи теряются.
Redis с persistence или RabbitMQ решают эту проблему.
Чеклист
Чеклист
Проверка перед запуском в продакшен:
Все операции дольше нескольких секунд вынесены в фоновые задачи
Webhook-обработчик отвечает 200 OK за секунды, не дожидаясь обработки
Брокер (Redis, RabbitMQ, PostgreSQL) развёрнут и настроен
Повторы настроены с экспоненциальным backoff
Каждая задача логируется:
время добавления, время обработки, результат
Обработка идемпотентна
— повтор не создаёт дубликаты и не ломает данные
Алерт срабатывает при накоплении задач выше порога
Задачи после всех retry попадают в dead-letter queue
Воркеры можно добавлять горизонтально при росте нагрузки
Очередь переживает рестарт сервера
— persistence включён
Ссылки
Ссылки
- Документация: BullMQ — Node.js Queue on Redis
- Документация: RabbitMQ — Message Broker
- Документация: n8n — Workflow Automation