Делимся опытом создания робота-диспетчера на low-code платформе. Прошли путь от простой идеи до архитектуры "Мастер-Воркер" для обработки большого потока заказов. Разбираем ошибки, технические решения и показываем готовые workflow.

Привет, меня зовут Арина, я фулстек разработчик. Мы разрабатываем высоконагруженный сервис для доставки еды, и сегодня я хочу рассказать, как мы автоматизировали один из самых рутинных участков с помощью n8n.

Введение: Проблема ручной фильтрации заказов

  • Исходная ситуация: Наш сервис получает большой поток заказов, особенно в пиковые часы. Значительная их часть (около 70%) — стандартные, не требующие особого внимания. Однако они попадали в общую очередь к операторам, которые тратили время на их рутинную проверку и отправку в производство (систему r‑keeper). Это замедляло обработку как простых, так и сложных заказов.

  • Постановка задачи: Разработать автоматизированное решение («робота»), которое возьмет на себя первичную фильтрацию:

    1. Автоматически валидировать и отправлять «простые» заказы в RK.

    2. Передавать операторам только те заказы, которые требуют их внимания, с указанием причины.

  • Выбор инструмента: Мы выбрали n8n как low‑code платформу для быстрой реализации MVP. Это позволило нам, не привлекая ресурсы основной фронтенд и бэкенд команд, интегрироваться с нашими сервисами (PostgreSQL, Redis, внутренние API) и быстро внедрить в продакшен.

Архитектура: "Мастер-Воркер"


Мы выбрали паттерн «Producer‑Consumer». Система состоит из двух типов workflow: одного «Мастера», который готовит данные, и нескольких «Воркеров», которые их обрабатывают.

  1. Роль Мастера: Запускается по расписанию (раз в 5 секунд), забирает из БД пачку (до 200) заказов. Проводит быструю предварительную фильтрацию по данным, уже имеющимся в заказе (бренд, комментарий, тип времени). Заказы, прошедшие фильтр, помещает в очередь в Redis. Непрошедшие — сразу отправляет операторам.

  2. Роль Воркеров (3-5 экземпляров): Запускаются очень часто (каждую секунду). Атомарно (LPOP) извлекают один ID заказа из очереди. Если заказ получен, Воркер выполняет полную, «дорогую» проверку, включающую запросы к внешним API (стоп‑листы, доступность блюд, время готовки, доступность ресторана).

Технические детали реализации в n8

Диаграмма компонентов
Диаграмма компонентов

Гибкая настройка правил: Управляем роботом, не трогая код

Одной из ключевых задач было создать систему, которую можно было бы гибко настраивать «на лету», не привлекая разработчиков для изменения каждого параметра. Мы хотели дать администраторам и менеджерам возможность самим решать, какие заказы считать «простыми».

Сущность №1: parameters — "Инструкция" для интерфейса

Это мозг нашей системы управления. parameters — это JSON, который хранится в Redis и описывает все возможные правила, которые робот в принципе умеет проверять. Также он служит инструкцией для нашего фронтенда на Vue.js.

Это текущие, «боевые» настройки, которые сохраняет администратор. active_rules — это тоже JSON в Redis, который читает сам робот (и Мастер, и Воркеры) при каждой проверке.

// Правил на самом деле больше, тут даны для примера
[
  {
    "id": "amount_to_pay",
    "label": "Сумма к оплате меньше (<=, руб)",
    "type": "number",
    "default_value": 3500
  },
  {
    "id": "brand_ids",
    "label": "Бренды (должен входить в список)",
    "type": "multiselect",
    "source": {
      "type": "rest",
      "endpoint": "/api/v1/brands",
      "value_field": "id",
      "label_field": "name"
    }
  }
]

Сущность №2: active_rules — "Приказ" для робота

Это текущие, «боевые» настройки, которые сохраняет старший оператор коллцентра. active_rules — это тоже JSON в Redis, который читает сам робот (и Мастер, и Воркеры) при каждой проверке.

[
  {
    "param_id": "amount_to_pay",
    "value": 3500,
    "is_active": true
  },
  {
    "param_id": "brand_ids",
    "value": ["brand1-uuid", "brand2-uuid"],
    "is_active": true
  }
]

Эта связка из двух JSON‑объектов дала нам невероятную гибкость. Мы можем менять логику робота «на лету», а добавление новых правил сводится к обновлению схемы и дописыванию пары строк в Code‑узле робота, без затрагивания остальной части системы. И у нас нет необходимости перерисовывать интерфейс

Интерфейс для настройки старшим оператором
Интерфейс для настройки старшим оператором

Анатомия Воркера

Задача Воркера проста: взять одну задачу (ID заказа) и довести ее до логического конца — либо отправить в RK, либо отдать оператору. Workflow Воркера, хоть и запускается каждую секунду, большую часть времени «спит». Он оживает, только когда в очереди Redis появляется работа.

Воркер в n8n
Воркер в n8n

Шаг 1: Захват задачи

  1. Schedule Trigger: Запускается каждую секунду.

  2. Redis (LPOP): Воркер делает атомарную операцию LPOP (или SPOP) к очереди robot:queue. LPOP — идеальный выбор для очереди «первый пришел — первый ушел». Если в очереди есть ID, он забирает его и сразу удаляет, гарантируя, что ни один другой Воркер этот ID уже не получит. Если очередь пуста, узел возвращает null, и workflow тихо завершается до следующей секунды.

  3. IF (Got an Order?): Простая проверка, не вернул ли LPOP пустоту. Если ID получен, начинается основная работа.

Шаг 2: Сбор данных ("Обогащение")

Прежде чем принимать решение, нам нужна полная картина. Одного ID недостаточно. Воркер последовательно собирает все необходимые данные:

  1. API (Get order): По полученному ID запрашивает из cуществующего API полную информацию о заказе (состав, адреса, комментарии, цены).

  2. Redis (GET): Загружает актуальные active_rules, чтобы знать, по каким правилам сегодня работаем.

  3. Цепочка HTTP Request'ов к внутренним API: Это самый «дорогой» этап, который и оправдывает вынесение логики в отдельный Воркер.

    • Получение актуального времени ресторана

    • Получения актуального времени готовки и доставки

    • Получение стоп‑листа ресторана

На этом этапе мы собрали всё «досье» на заказ. Если на любом из этих шагов происходит ошибка (например, API недоступен), заказ автоматически считается «проблемным» и уходит оператору.

Шаг 3: Принятие решения (узел Code)

Вся логика проверки инкапсулирована в одном узле Code. Это позволяет нам писать сложный код на JavaScript, не загромождая workflow десятками IF‑узлов. Проверка идет последовательно, «лесенкой». Если заказ не проходит хотя бы один шаг, остальные уже не выполняются.

Уровень 1: Динамические правила из Redis. Применяются настроенные правила:

  • Сумма заказа меньше или равна X?

  • Бренд входит в разрешенный список?

  • Комментарий действительно пуст?

  • Ресторан не в списке исключений?

Уровень 3: Проверки по обогащенным данным. Самые последние и сложные проверки:

  • Актуальное время готовки, полученное из API, меньше Y?

  • Нет ли в заказе блюд из стоп‑листа, полученного по API?

  • Есть ли вообще доступные интервалы для доставки?

На выходе узел Code возвращает простой объект: { «isMatch»: true/false, «reason»: «...» }.

Шаг 4: Исполнение

  1. IF (Final Match?): Проверяет флаг isMatch.

  2. Ветка true:

    • HTTP Request (PUT): Обновляет заказ, проставляя полученное время.

    • HTTP Request (POST): Отправляет финальный, валидированный заказ в R‑Keeper.

  3. Ветка false:

    • Postgres (UPDATE): Меняем статус заказа на new, чтобы он появился у операторов.

    • Telegram: Отправляем уведомление с причиной, которую нам вернул узел Code (например, «Блюдо 'Цезарь' в стоп‑листе»).

Обработка ошибок и "красная кнопка": что делать, если робот сошел с ума

Любая сложная система рано или поздно сталкивается со сбоями. Нашей задачей было не предотвратить их на 100% (что невозможно), а построить надежный механизм реакции на них. Мы реализовали два уровня защиты: автоматический отлов ошибок и ручной «аварийный тормоз».

Автоматический отлов сбоев (Error Workflow)

Мы используем встроенную в n8n возможность — Error Workflow. Это отдельный, специальный workflow, который автоматически запускается, если в любом из наших основных workflow («Мастер» или «Воркер») происходит непредвиденная ошибка (например, упал внешний API, Redis вернул некоррктные данные, или произошел сбой в Code‑узле).

Ручной аварийный режим

Что делать, если робот начал вести себя непредсказуемо, но формально не выдает ошибок? Например, начал массово отбраковывать хорошие заказы из‑за неправильно настроенного правила. Для таких случаев у нас есть «красная кнопка» — отдельный webhook для экстренной остановки.

Красная кнопка для администратора
Красная кнопка для администратора

Этот «аварийный тормоз» позволяет любому авторизованному администратору со страницы управления в ЕДС одним кликом полностью остановить всю автоматизацию и вернуть систему в 100% ручной режим за несколько секунд (пока не использовали;))

Результаты и выводы

  • Результаты: После внедрения мы сократили среднее время обработки простого заказа с 3–5 минут до ~6 секунд. Это позволило снизить нагрузку на операторов в пиковые часы и уменьшить количество просроченных по времени приготовления заказов

  • Ключевые направления развития:

    1. Интеграция с телефонией Наш следующий шаг — это информирование гостей через API сервиса телефонии, чтобы предупредить о задержке. Это позволит снять нагрузку с операторов и повысить качество клиентского сервиса.

    2. Интеграция с предиктивными моделями. Мы рассматриваем возможность подключения ML‑моделей для обогащения проверок. Например, робот сможет оценивать заказ на предмет потенциального фрода или прогнозировать вероятность отказа клиента на основе истории, передавая подозрительные случаи оператору для дополнительной верификации.

    3. Динамическое управление нагрузкой. В будущем робот сможет принимать решения не только на основе данных самого заказа, но и с учетом внешнего контекста: текущей загруженности ресторана, дорожной ситуации в зоне доставки или даже погодных условий, временно ужесточая или ослабляя правила фильтрации.

  • Краткий итог: n8n показал себя как гибкий инструмент для быстрой реализации сложных систем оркестрации. Архитектура «Мастер‑Воркер» позволила нам построить масштабируемое и отказоустойчивое решение для задачи с высокой интенсивностью потока данных.

Комментарии (0)