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Агент обрабатывает сразу, риск таймаута 504Webhook кладёт задачу, воркер обрабатывает в фоне
Отправка 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 включён

Ссылки

Ссылки