Уведомления команде в мессенджер - вебхук, шаблон, ошибки
Отправляем уведомления о заказах и заявках в рабочий чат: хранение токена, отправка из события, вынос в фон и разумные ограничения потока.
Что нужно знать заранее
Мессенджер - это обычный внешний сервис с программным интерфейсом. Отправка сообщения ничем не отличается от вызова любого чужого API: адрес, токен, тело запроса и разбор ответа.
Отправку сообщения нельзя ставить в шаблон страницы или в цикл вывода. Чужой сервис отвечает десятые доли секунды в лучшем случае, а при недоступности держит запрос до предела времени ожидания.
Сообщения быстро превращаются в шум, если отправлять в общий чат всё подряд. В чат отправляют события, требующие действия человека, а сводки и отчёты оставляют почте и административному разделу.
Шаги
- Получить токен доступа у мессенджера и записать его в настройки своего проекта.
- Выбрать события, при которых сообщение действительно нужно живому человеку сейчас.
- Отправлять сообщение из обработчика события, а не из шаблона страницы витрины.
- Вынести отправку в фон и добавить короткий повтор при временном отказе сервиса.
- Ограничить поток так: одно сообщение на событие и сводка вместо потока мелочей.
Решение
Храним токен в настройках проекта:
// /bitrix/.settings_extra.php стенда: свои значения поверх общихreturn ['vendor_chat' => ['value' => [ 'url' => 'https://api.example.com/bot%s/sendMessage', 'token' => '***', 'chat_id' => '-1001234567890',], 'readonly' => true]];Токен - такой же секрет, как пароль от базы. В репозиторий он не попадает, а на стенде подменяется тестовым чатом, чтобы проверки не сыпались в рабочую группу менеджеров.
Отправляем сообщение из кода:
$config = \Bitrix\Main\Config\Configuration::getValue('vendor_chat');$http = new \Bitrix\Main\Web\HttpClient(['socketTimeout' => 3, 'streamTimeout' => 5]);$answer = $http->post(sprintf($config['url'], $config['token']), [ 'chat_id' => $config['chat_id'], 'text' => sprintf("Заказ №%s на %s ₽", $order->getField('ACCOUNT_NUMBER'), $order->getPrice()),]);Короткие таймауты здесь обязательны. Недоступный мессенджер не должен удерживать процесс: сообщение подождёт в очереди, а покупатель дождётся страницы вовремя.
Ставим отправку на событие заказа:
\Bitrix\Main\EventManager::getInstance()->addEventHandler('sale', 'OnSaleOrderSaved', static function (\Bitrix\Main\Event $event) { $order = $event->getParameter('ENTITY'); if (!$event->getParameter('IS_NEW')) { return; } // только новые заказы \Bitrix\Main\Application::getInstance()->addBackgroundJob( static fn() => notifyChat($order)); // отправка после ответа странице });Событие сохранения заказа - естественная точка отправки. Проверка на новизну обязательна: без неё чат получает сообщение при каждом изменении заказа менеджером.
Повторяем при временном отказе:
for ($try = 1; $try <= 3; $try++) { $answer = $http->post($url, $data); if ($http->getStatus() === 200) { break; } sleep($try); // короткая пауза между попытками}\Bitrix\Main\Diag\Debug::writeToFile($http->getStatus(), date('H:i:s'), 'chat.log');Три попытки с паузой закрывают короткие сбои сети. Дальше сообщение честно считают недоставленным и пишут в журнал: бесконечные повторы забивают очередь и ничего не чинят.
Ограничиваем поток сообщений:
$key = 'vendor.chat.last_' . $orderId;if ($storage->get($key, false)) { return; } // не дублируем сообщение по заказу$storage->set($key, 1, 3600);Защита от повторов важнее красоты текста. Одно событие - одно сообщение, иначе при обмене с учётной системой чат за минуту наполняется десятками одинаковых строк.
Типичные проблемы
Оформление заказа стало заметно медленнее.
Сообщение отправляется прямо в запросе покупателя, ещё до ответа самой страницы. Отправку выносят в фоновое задание, которое выполняется после отдачи ответа.
Чат завален одинаковыми сообщениями.
Обработчик срабатывает при каждом сохранении заказа, а не только при его создании. Проверяют признак нового заказа и отдельно защищаются от повторных отправок.
Токен уехал в репозиторий.
Ключ доступа записан прямо в коде обработчика события сохранения заказа. Секреты держат в файле настроек проекта, который в репозиторий никогда не попадает.
Сообщения перестали приходить после смены чата.
Изменился идентификатор чата, а в настройках проекта остался прежний старый. Идентификатор чата хранят в настройках и проверяют после любых изменений в мессенджере.
При недоступности сервиса падает оформление.
Ошибка отправки не перехвачена и всплывает наверх до самого посетителя. Отправку оборачивают обработкой ошибок: чат не должен ломать оформление заказа.
Частые вопросы
Чем это лучше письма менеджеру?
Сообщение в чат приходит мгновенно и видно всей смене. Письма удобнее для подробных сводок и для истории, поэтому каналы обычно совмещают.
Что писать в сообщении?
Минимум для решения: номер, сумму, имя и ссылку на карточку в админке. Подробности смотрят по ссылке, а не читают в чате.
Как не спамить в чат ночью?
Проверять время перед отправкой и копить ночные события в сводку. Срочные события шлют всегда, остальные - утром одним сообщением.
Нужна ли очередь для таких уведомлений?
На небольшом потоке хватает фонового задания. Очередь нужна там, где событий много и важно не потерять ни одного сообщения.
Как проверить настройку до боевого запуска?
Отправить тестовое сообщение в отдельный чат из консольного скрипта. Так проверяется и токен, и доступ сервера к интернету.
Смежное
-
REST и вебхуки - оглавление подтемы
-
Запрос к внешнему сервису не проходит: разбор причин - если сообщения не уходят вовсе
-
Вызов внешнего сервиса из кода: таймауты, повторы, журнал - общая механика вызова
-
Приём вебхука от внешнего сервиса: точка входа, подпись, повторы - обратное направление
-
Очередь сообщений: фоновая обработка задач в ядре - когда событий много
-
Уведомления покупателю: письма и SMS по статусам заказа - уведомления второй стороне
-
Настройки проекта: файл ядра, опции модуля, разные стенды - где хранить токен
-
Обмен с 1С и HTTP - устройство интеграций целиком
-
Сбор ошибок сайта в одном месте: перехват, уведомление, секреты - уведомления об ошибках без шторма сообщений
-
Уведомления менеджеру: письмо, чат, эскалация по времени - что именно отправляют команде магазина