Перейти к содержимому

Уведомления команде в мессенджер - вебхук, шаблон, ошибки

Отправляем уведомления о заказах и заявках в рабочий чат: хранение токена, отправка из события, вынос в фон и разумные ограничения потока.

Что нужно знать заранее

Мессенджер - это обычный внешний сервис с программным интерфейсом. Отправка сообщения ничем не отличается от вызова любого чужого API: адрес, токен, тело запроса и разбор ответа.

Отправку сообщения нельзя ставить в шаблон страницы или в цикл вывода. Чужой сервис отвечает десятые доли секунды в лучшем случае, а при недоступности держит запрос до предела времени ожидания.

Сообщения быстро превращаются в шум, если отправлять в общий чат всё подряд. В чат отправляют события, требующие действия человека, а сводки и отчёты оставляют почте и административному разделу.

Шаги

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

Решение

Храним токен в настройках проекта:

// /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);

Защита от повторов важнее красоты текста. Одно событие - одно сообщение, иначе при обмене с учётной системой чат за минуту наполняется десятками одинаковых строк.

Типичные проблемы

Оформление заказа стало заметно медленнее.

Сообщение отправляется прямо в запросе покупателя, ещё до ответа самой страницы. Отправку выносят в фоновое задание, которое выполняется после отдачи ответа.

Чат завален одинаковыми сообщениями.

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

Токен уехал в репозиторий.

Ключ доступа записан прямо в коде обработчика события сохранения заказа. Секреты держат в файле настроек проекта, который в репозиторий никогда не попадает.

Сообщения перестали приходить после смены чата.

Изменился идентификатор чата, а в настройках проекта остался прежний старый. Идентификатор чата хранят в настройках и проверяют после любых изменений в мессенджере.

При недоступности сервиса падает оформление.

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

Частые вопросы

Чем это лучше письма менеджеру?

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

Что писать в сообщении?

Минимум для решения: номер, сумму, имя и ссылку на карточку в админке. Подробности смотрят по ссылке, а не читают в чате.

Как не спамить в чат ночью?

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

Нужна ли очередь для таких уведомлений?

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

Как проверить настройку до боевого запуска?

Отправить тестовое сообщение в отдельный чат из консольного скрипта. Так проверяется и токен, и доступ сервера к интернету.

Смежное

Первоисточник