Как чат-боту отправлять уведомления из CRM без дублей?

Как чат-боту отправлять уведомления из CRM без дублей?

Начните с правила: каждому уведомлению о заказе нужен постоянный ключ, который сохраняется при повторной обработке. Затем свяжите CRM и чат-бота через журнал событий и очередь задач. Журнал поможет узнать повтор, а очередь сохранит работу при сбое. Но одной очереди недостаточно: после потери ответа нельзя вслепую отправлять сообщение заново. Ниже разберём, как описать события заказа, настроить повторные попытки и проверить интеграцию до запуска, чтобы клиент не получал одинаковые сообщения из-за повторного запроса.

Почему чат-бот повторно сообщает о статусе заказа?

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

Повтор возникает и без обрыва связи: менеджер ещё раз сохраняет карточку, интеграция повторно передаёт событие или обработчик возвращается к задаче после перезапуска. Поэтому запретить повторы на стороне одной CRM недостаточно. Получатель тоже должен узнавать событие, с которым уже работал.

Уведомления нужны клиенту, чтобы понимать, что происходит с заказом. Когда прозрачных статусов нет, клиент обращается в чат и добавляет работу менеджеру. Запуск без тестовой группы тоже создаёт риск ошибок в момент высокой нагрузки — эти проблемы отмечает материал об автоматизации продаж через Telegram-бот для интернет-магазина в Беларуси (ibz.by). В тестах стоит проверять и содержание сообщений, и реакцию бота на повтор одного события.

Сначала найдите место, где рождается дубль. Если CRM создала две сделки, проверяйте приём заявки. Если сделка одна, а сообщений несколько, проверяйте путь от смены статуса до отправки. Для первого случая полезен отдельный разбор того, как чат-боту собрать одну заявку из нескольких сообщений: защита заявки и защита уведомления требуют разных ключей.

Как определить, какое сообщение считать повторным?

Опишите событие словами до настройки интеграции. Например: «Бот сообщает о готовности заказа, когда заказ впервые перешёл в статус “Готов к выдаче”». Повторное сохранение карточки с тем же статусом не создаёт нового уведомления. А сообщение об отмене относится уже к другому событию.

Такое описание помогает выбрать ключ — техническую метку, по которой система узнаёт уведомление. Один номер заказа для этого слишком общий: он заблокирует последующие сообщения об оплате или выдаче. Случайный новый ключ при каждом запросе тоже не подходит: с ним каждый повтор выглядит новым событием.

  • Укажите заказ, к которому относится уведомление.
  • Добавьте тип события, например готовность к выдаче или отмену.
  • Включите идентификатор перехода, если заказ может снова попасть в тот же статус и клиенту нужно новое сообщение.
  • Разделяйте уведомления по каналу, если для события предусмотрены независимые отправки.

Лучше использовать постоянный идентификатор события из CRM, если она его передаёт. Если такого идентификатора нет, разработчику нужно определить правило, которое отличает повтор запроса от нового перехода. Время поступления запроса для этого не годится: повтор придёт позже и получит другую метку.

Согласуйте также, какая система отвечает за статус. Если чат-бот принимает заявку, а менеджер ведёт заказ в CRM, источником события о готовности обычно становится CRM. Этот порядок удобно описать вместе с правилами, по которым чат-бот квалифицирует лиды и передаёт их в CRM, чтобы не создавать параллельные сценарии в боте и отделе продаж.

Как связать CRM, журнал и очередь?

Журнал хранит историю конкретного уведомления, а очередь передаёт задачу обработчику отправки. Защиту, при которой повторная обработка не создаёт нового действия, называют идемпотентностью. Для владельца бизнеса её смысл простой: один и тот же запрос можно принять повторно без новой отправки.

Передайте разработчику такую последовательность:

  1. Сохранить событие с постоянным ключом и уникальным ограничением в базе. При конфликте ключа вернуть существующую запись.
  2. В той же операции базы сохранить задание на отправку. Отдельный процесс сможет передать его в очередь, даже если сразу после записи произойдёт сбой.
  3. Перед отправкой закрепить запись за обработчиком одним неделимым действием, чтобы параллельные процессы не начали работу одновременно.
  4. Записать результат обращения к сервису сообщений и его идентификатор, если сервис его вернул.
  5. Подтвердить выполнение задачи в очереди после сохранения результата.

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

Для небольшого проекта журнал и задания можно разместить в существующей базе. Отдельную инфраструктуру выбирают под нагрузку и условия сопровождения. Подробности этой схемы разобраны в статье на adsl.by; при постановке задачи полезнее проверить поведение после сбоя, чем заранее выбирать название технологии.

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

Что делать, если сервис сообщений не ответил?

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

Таймаут означает другое: система не дождалась ответа. Сервис уже мог принять сообщение и отправить его клиенту. Поэтому автоматическая новая отправка после любого таймаута создаёт риск дубля.

Для такого случая предусмотрите состояние «результат неизвестен». Сначала запросите результат предыдущей попытки, если сервис позволяет найти её по идентификатору сообщения или клиентскому ключу. Если сервис поддерживает идемпотентную отправку, повторяйте запрос с прежним ключом по его документации. Локальная запись в вашей базе сама по себе не заставляет внешний сервис распознавать повторы.

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

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

Какие типичные ошибки проверить перед запуском?

Проверяйте интеграцию на тестовом заказе и в контрольном чате. Сначала убедитесь, что обычная смена статуса запускает нужное сообщение. Затем воспроизведите сбои: повторите событие, передайте его параллельно и перезапустите обработчик во время работы.

  • Новый ключ при повторе. Исправление: сохранять ключ исходного события во всех попытках.
  • Запись в журнале после отправки. Исправление: создавать запись заранее, иначе сбой оставит отправку без истории.
  • Повтор после любого таймаута. Исправление: выделить неизвестный результат и проверять предыдущую попытку.
  • Слишком раннее удаление ключей. Исправление: хранить их с учётом периода, в течение которого CRM и очередь ещё могут повторить событие.
  • Отправка устаревшего статуса после долгого сбоя. Исправление: перед отправкой проверять актуальность сообщения по заранее согласованному правилу.

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

Проверка пройдена, когда повтор события находит одну запись уведомления, параллельные обработчики не начинают независимые отправки, а неизвестный результат остаётся виден ответственному. Затем переведите тот же тестовый заказ в другой статус: новое нужное сообщение должно пройти. Так вы проверите, что защита от дублей не блокирует дальнейшее общение.

Сейчас выделите две минуты: выберите одно уведомление в CRM и запишите правило «какое событие запускает сообщение и по какому ключу бот узнаёт его повтор». Передайте эту формулировку разработчику как первое условие проверки интеграции.