Все материалы

Очереди сообщений в Bitrix Framework: как вынести интеграцию из запроса пользователя

Как вынести синхронизацию с Google Calendar из запроса пользователя в очередь Bitrix Framework: сообщение, обработчик, настройки модуля и брокера, запуск воркера. Разбираем режимы web и cli и что проверить перед запуском в работу.

Очереди сообщений в Bitrix Framework: как вынести интеграцию из запроса пользователя

Сотрудник изменил событие в календаре Битрикс24. Теперь его нужно передать в Google Calendar. Если обращаться к внешнему API прямо в запросе, сотрудник будет ждать ответа Google вместе с сохранением события. При задержке или сбое интеграции пострадает и основное действие. Очередь позволяет завершить запрос после сохранения изменений, а синхронизацию выполнить отдельно.

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

Механизм очередей доступен с версии main 25.100.300. В документации Bitrix Framework он пока помечен как альфа-функция без гарантии обратной совместимости. Перед внедрением проверьте версию главного модуля и изменения API при последующих обновлениях. Генераторы классов make:message и make:messagehandler появились позже, с версии main 25.900.0. Если их нет, классы можно написать вручную.

Что происходит с сообщением

У очереди четыре основных участника:

Участник Задача в нашем примере
Сообщение Передаёт ID события, ID календаря Google и тип операции.
Очередь Связывает сообщения google_event_sync с нужным обработчиком.
Брокер Хранит сообщение до обработки. Сейчас поддерживается тип db, то есть хранение в базе данных.
Воркер и обработчик Воркер забирает сообщение, обработчик выполняет работу с его данными.

После изменения события код вызывает send(). Сообщение сохраняется у брокера. Позже воркер передаёт его обработчику, и тот выполняет синхронизацию или, как в учебном примере, пишет в лог.

Как работает очередь сообщений в Bitrix Framework

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

Режимы обработки очередей: web и cli

1. Создаём сообщение

Класс можно сгенерировать из каталога /bitrix/ проекта:

php bitrix.php make:message GoogleEventSync -m my.module -n

В сгенерированном классе оставим данные, нужные обработчику:

use Bitrix\Main\Messenger\Entity\AbstractMessage;

class GoogleEventSyncMessage extends AbstractMessage
{
    public function __construct(
        public readonly int $eventId,
        public readonly string $externalCalendarId,
        public readonly string $operation,
    ) {}
}

AbstractMessage автоматически сохраняет и восстанавливает поля простых типов. Здесь это int и string, поэтому отдельные методы сериализации не требуются. Если в сообщение нужно положить сложные данные, реализуйте jsonSerialize() для преобразования в JSON-совместимый массив и createFromData() для восстановления объекта:

use Bitrix\Main\Messenger\Entity\MessageInterface;

public function jsonSerialize(): mixed
{
    return [
        'eventId' => $this->eventId,
        'externalCalendarId' => $this->externalCalendarId,
        'operation' => $this->operation,
    ];
}

public static function createFromData(array $data): MessageInterface
{
    return new static(...$data);
}

Это фрагмент для класса сообщения выше, а не самостоятельный PHP-файл. Например, после сериализации данные будут выглядеть так: {"eventId":123,"externalCalendarId":"google-calendar-42","operation":"update"}. Сам объект сообщения ничего не отправляет в Google: он только переносит данные между отправителем и обработчиком.

2. Создаём обработчик

Если генератор доступен, создадим заготовку:

php bitrix.php make:messagehandler GoogleEventSync --handler-module=my.module --message-module=my.module -n

Обработчик наследуется от AbstractReceiver. Метод process() получит сообщение и выполнит действие. Для проверки запишем значения в настроенный логгер:

use Bitrix\Main\Diag\LoggerFactory;
use Bitrix\Main\Messenger\Entity\MessageInterface;
use Bitrix\Main\Messenger\Receiver\AbstractReceiver;

class GoogleEventSyncMessageHandler extends AbstractReceiver
{
    /** @param GoogleEventSyncMessage $message */
    protected function process(MessageInterface $message): void
    {
        $logger = (new LoggerFactory())->createDefault();
        if ($logger === null) {
            throw new \RuntimeException('Настройте логгер для проверки очереди');
        }

        $logger->info(sprintf(
            'Google Calendar sync: event %d, calendar %s, operation %s',
            $message->eventId,
            $message->externalCalendarId,
            $message->operation,
        ));
    }
}

Здесь для краткости опущены namespace и загрузка классов: их нужно взять из структуры вашего модуля или из сгенерированных файлов. Настройте логирование до проверки примера. Если process() завершился без исключения, сообщение считается обработанным. При ошибке обработчик должен выбросить исключение; повторы настраиваются отдельно.

3. Регистрируем очередь в модуле

В .settings.php модуля my.module добавим секцию messenger. Если файл уже содержит настройки, дополните существующий массив, не заменяя его целиком:

return [
    // Другие настройки модуля.
    'messenger' => [
        'value' => [
            'queues' => [
                'google_event_sync' => [
                    'handler' => \My\Module\MessageHandler\GoogleEventSyncMessageHandler::class,
                ],
            ],
        ],
        'readonly' => true,
    ],
];

Путь в handler примерный: укажите фактическое полное имя класса в вашем модуле. Имя google_event_sync понадобится при отправке сообщения и запуске воркера. readonly запрещает менять эти настройки через API. Если для очереди не задан свой брокер, используется default.

4. Настраиваем брокер и режим запуска

Общие параметры находятся в /bitrix/.settings.php. Добавим консольный режим и брокер на базе СУБД, сохранив остальные секции файла:

return [
    // Другие настройки проекта.
    'messenger' => [
        'value' => [
            'run_mode' => 'cli',
            'brokers' => [
                'default' => [
                    'type' => 'db',
                    'params' => [
                        'table' => \Bitrix\Main\Messenger\Internals\Storage\Db\Model\MessengerMessageTable::class,
                    ],
                ],
            ],
        ],
        'readonly' => true,
    ],
];

run_mode отвечает за способ обработки. Брокер default обязателен в глобальной конфигурации; сюда попадут сообщения нашей очереди. Если глобальная секция messenger уже создана системой, проверьте её и измените нужные поля, не дублируя ключ.

5. Отправляем и обрабатываем сообщение

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

$message = new GoogleEventSyncMessage(
    $eventId,
    $externalCalendarId,
    'update',
);
$message->send('google_event_sync');

Идентификатор в send() должен в точности совпадать с ключом очереди в конфигурации модуля. Вызов сохраняет задачу у брокера; он не означает, что Google Calendar уже обновлён.

В каталоге /bitrix/ запустим воркер для этой очереди:

php bitrix.php messenger:consume google_event_sync

Без указания имени команда обслуживает все очереди. Консольный воркер работает в цикле; для ограниченного диагностического запуска можно задать время работы через -t. Когда обработчик получит тестовое сообщение, в логе, настроенном для LoggerFactory, ожидается строка вида:

Google Calendar sync: event 123, calendar google-calendar-42, operation update

Проверяйте именно настроенный логгер. В исходном примере финальная фраза предлагает искать запись AddMessage2Log(), хотя показанный обработчик использует LoggerFactory; это разные способы записи. Если файл лога пуст, сначала проверьте конфигурацию логгера, запуск воркера и наличие сообщения в очереди.

Что добавить перед запуском интеграции в работу

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

Пять проверок перед запуском очереди Bitrix Framework
  • Повторные попытки. Google Calendar может временно не отвечать. Для очереди настраивается retry_strategy: число попыток, начальная задержка, её множитель и максимальная задержка. Обработчик должен корректно сообщать об ошибке исключением.
  • Изменение исходных данных. Между отправкой и обработкой проходит время. Событие может измениться или исчезнуть; заранее определите, какие данные сохранять в сообщении, а какие заново читать перед запросом к API.
  • Нагрузка. Параметр limit ограничивает число сообщений за один проход, total_processing_limit — их одновременную обработку всей очередью. Второе значение не должно быть меньше первого.
  • Хранение и расписание. При необходимости можно выделить отдельную таблицу для сообщений модуля или отложить обработку. Создание собственной таблицы нужно включить в установщик модуля.
  • Работа воркера. В режиме cli настройте постоянный запуск, перезапуск при сбое и наблюдение за ошибками. Иначе сообщения будут накапливаться в базе без обработки.

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

Подробности параметров и ограничений: очереди сообщений, консольные команды и логгеры в документации Bitrix Framework.

Нужно внедрить очереди сообщений в Битрикс?

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

Написать в SolverWeb ↗

Полезен материал?

Оценок пока нет — будьте первым.

Обсуждение

Поделитесь мнением — первый комментарий задаст тон.

0

Оставить комментарий

Он появится после короткой проверки модератором.

* обязательные поля