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

SMS и очереди сообщений в 1С-Битрикс

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

Как это работает

У SMS два уровня API. Высокий уровень работает как почтовые события: код создаёт событие с данными, система находит активный шаблон по имени события, сайту и языку, подставляет значения вместо меток и передаёт готовое сообщение службе. Текст живёт в шаблоне, и его правит администратор - код передаёт только данные. Низкий уровень - прямая отправка через менеджер провайдеров: выбор провайдера, отправка текста, проверка статуса доставки.

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

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

Примеры

1. SMS через событие и шаблон

use Bitrix\Main\Sms\Event;
$event = new Event('SMS_USER_CONFIRM_NUMBER', [
'USER_PHONE_NUMBER' => $phone,
'CODE' => $confirmationCode,
]);
$event->send();

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

2. Прямая отправка

use Bitrix\MessageService\Sender\SmsManager;
$result = SmsManager::sendMessage([
'SENDER_ID' => $senderId,
'MESSAGE_TO' => $phone,
'MESSAGE_BODY' => 'Ваш заказ отправлен',
]);
if (!$result->isSuccess()) {
// разбор ошибок
}

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

3. Своё сообщение в очереди

use Bitrix\Main\Messenger\Entity\AbstractMessage;
use Bitrix\Main\Messenger\Entity\MessageInterface;
class OrderExportMessage extends AbstractMessage
{
public function __construct(
public readonly int $orderId,
) {}
public function jsonSerialize(): mixed
{
return ['orderId' => $this->orderId];
}
public static function createFromData(array $data): MessageInterface
{
return new static(...$data);
}
}
class OrderExportReceiver extends AbstractReceiver
{
protected function process(MessageInterface $message): void
{
$this->exporter->export($message->orderId);
}
}

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

Справочник API

APIНазначениеОсобенности
Main\Sms\EventSMS через событие и шаблонмодель как у почтовых событий
MessageService\Sender\SmsManagerпрямая отправкавыбор провайдера, статус доставки
SmsManager::getSenders()список провайдеровтолько поддерживаемые конфигурацией
MessageService\Sender\Baseбазовый класс провайдерадля своей интеграции
событие регистрации провайдеровподключение своего отправителя
Main\Messengerочереди сообщенийсообщение, получатель, конфигурация транспорта
AbstractMessageсвоё сообщениесериализация и восстановление из данных
AbstractReceiverобработчикметод обработки одного сообщения

Частые ошибки

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

Метки в тексте остались как есть. Имена ключей в переданных данных не совпадают с метками шаблона.

Провайдер не появляется в списке. Он не поддерживается текущей конфигурацией либо свой класс не зарегистрирован событием.

Тяжёлая работа выполняется в запросе. Экспорт, рассылка, обращение к медленному внешнему сервису - кандидаты в очередь, а не в обработчик формы.

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

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

Событие с шаблоном или прямая отправка SMS?

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

Что выносить в очередь?

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

Как добавить своего SMS-провайдера?

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

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

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

Связанные темы

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