Как мгновенно оповестить клиентский сеанс 1С о событии на сервере?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие часто возникает классическая задача: внешняя система (например, телефония, сайт, ERP-система или чат-бот) отправляет запрос на HTTP-сервис 1С. В результате этого запроса серверная часть 1С должна моментально «сгенерировать» действие в конкретном открытом сеансе пользователя — открыть форму, обновить динамический список, запустить локальный скрипт или вывести интерактивное предупреждение. Для автоматизации выполнения подобных операций в интерфейсе можно использовать платформу для визуального создания программных роботов.

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

Вариант 1. Классический опрос по таймеру (Обработчик ожидания + Регистр)

Это самый старый, проверенный временем, но при этом наименее производительный способ. Суть его заключается в организации буфера обмена (как правило, на базе регистра сведений) и периодического «опрашивания» этого буфера клиентом.

Схема работы решения:

  1. Внешний сервис стучится на HTTP-сервис 1С.
  2. Код HTTP-сервиса обрабатывает запрос и записывает событие в специальный регистр сведений (например, ОчередьСобытийДляКлиентов), указывая получателем конкретного пользователя.
  3. На клиенте при начале работы системы запускается фоновый обработчик ожидания с определенным интервалом (например, каждые 5–10 секунд).
  4. При срабатывании обработчик делает вызов сервера, считывает данные из регистра, обрабатывает их и очищает очередь.

Рассмотрим пример реализации клиентской части:


Процедура ПриНачалеРаботыСистемы() Экспорт
    // Подключаем обработчик, который будет срабатывать каждые 10 секунд
    ПодключитьОбработчикОжидания("ПроверитьНовыеСобытияСервера", 10, Ложь);
КонецПроцедуры

Процедура ПроверитьНовыеСобытияСервера() Экспорт
    // Вызываем серверную функцию получения событий
    СписокСобытий = ПолучитьНовыеСобытияИзРегистра();
    
    Если СписокСобытий.Количество() > 0 Тогда
        Для Каждого Событие Из СписокСобытий Цикл
            ОбработатьВнешнееСобытиеНаКлиенте(Событие);
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

Плюсы: простота реализации, надежность, сохранение истории событий в базе данных (если клиент не в сети, данные не пропадут и будут обработаны при следующем запуске). Такой механизм гарантированной доставки удобен, например, при отправке уведомлений о заказах Wildberries по схеме FBS.

Минусы: постоянная фоновая нагрузка на СУБД из-за регулярных запросов сотен пользователей. Либо мы получаем задержку в получении сообщений (если интервал большой), либо просадку производительности сервера (если интервал опроса слишком маленький).

Вариант 2. Использование Системы взаимодействия (WebSocket)

Если вам требуется мгновенная реакция без лишней нагрузки на базу данных, правильным решением будет использование Системы взаимодействия (встроенный в платформу механизм мгновенных сообщений и видеозвонков).

Система взаимодействия работает по протоколу WebSocket. Это значит, что клиентское приложение поддерживает постоянное открытое TCP-соединение с сервером. Мы можем использовать так называемые служебные (неотображаемые) обсуждения.

Алгоритм настройки:

  1. При старте системы клиентское приложение подписывается на сообщения из специального интеграционного обсуждения.
  2. В коде обработки HTTP-сервиса на стороне сервера мы программно создаем сообщение в это обсуждение и отправляем его адресату.
  3. Сервер взаимодействия моментально пересылает это сообщение в клиентский сеанс.
  4. На клиенте срабатывает обработчик ПриПолученииСообщения, который выполняет нужные алгоритмы без какого-либо периодического опроса базы данных.

Рассмотрим, как выглядит программная отправка сообщения с сервера:


// Серверный код (внутри метода HTTP-сервиса)
Процедура ОтправитьОповещениеПользователю(ИмяПользователя, ТекстОповещения) Экспорт
    
    // Находим нужного пользователя системы взаимодействия
    ПользовательСВ = СистемаВзаимодействия.ПолучитьПользователя(ИмяПользователя);
    
    Если ПользовательСВ <> Неопределено Тогда
        // Ищем существующее служебное обсуждение или создаем новое
        ПараметрыОтбора = Новый ПараметрыОтбораОбсуждений;
        ПараметрыОтбора.Ключ = "СлужебныйКанал_" + ИмяПользователя;
        
        ВыборкаОбсуждений = СистемаВзаимодействия.ВыбратьОбсуждения(ПараметрыОтбора);
        Если ВыборкаОбсуждений.Следующий() Тогда
            Обсуждение = ВыборкаОбсуждений.Получить();
        Иначе
            Обсуждение = СистемаВзаимодействия.СоздатьОбсуждение();
            Обсуждение.Ключ = "СлужебныйКанал_" + ИмяПользователя;
            Обсуждение.Участники.Добавить(ПользовательСВ);
            Обсуждение.Записать();
        КонецЕсли;
        
        // Создаем и отправляем сообщение
        НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
        НовоеСообщение.Текст = ТекстОповещения;
        НовоеСообщение.Записать();
    КонецЕсли;
    
КонецПроцедуры

Плюсы: реакция системы происходит мгновенно (доли секунды), отсутствует лишняя нагрузка на сервер СУБД, используется полностью штатный инструмент платформы.

Минусы: требуется развертывание локального Сервера взаимодействия (1С:Сервер взаимодействия) либо подключение к бесплатному облачному сервису 1С.

Вариант 3. Нативный механизм «Уведомления клиента» (Начиная с версии 8.3.26)

В новых версиях платформы (начиная с релиза 8.3.26) разработчики 1С добавили долгожданный механизм гарантированной доставки уведомлений с сервера на клиент без использования Системы взаимодействия. Для этого в глобальном контексте появился менеджер УведомленияКлиента.

Этот механизм позволяет серверной части «проталкивать» данные непосредственно в конкретные сеансы пользователей.

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


// В модуле управляемого приложения на клиенте
Процедура ПриНачалеРаботыСистемы()
    ОписаниеОповещения = Новый ОписаниеОповещения("ОбработатьСобытиеСервера", ЭтотОбъект);
    УведомленияКлиента.ПодключитьОбработчик("ВнешнийЗапросHTTP", ОписаниеОповещения);
КонецПроцедуры

Процедура ОбработатьСобытиеСервера(ИмяУведомления, Данные, Источник) Экспорт
    // Данные — это структура, переданная с сервера
    ПоказатьПредупреждение(, "Внимание! Получено уведомление: " + Данные.Сообщение);
КонецПроцедуры

Теперь на сервере, когда отрабатывает наш HTTP-сервис, мы можем отправить данные конкретному пользователю. Для этого нам нужно знать номера его активных сеансов:


// На сервере в модуле HTTP-сервиса
Процедура ОповеститьСеансыПользователя(ИмяПользователя, ТекстСообщения)
    
    ДанныеДляПередачи = Новый Структура("Сообщение", ТекстСообщения);
    МассивНомеровСеансов = Новый Массив;
    
    // Получаем список активных сеансов ИБ
    СеансыИнформационнойБазы = ПолучитьСеансыИнформационнойБазы();
    Для Каждого Сеанс Из СеансыИнформационнойБазы Цикл
        Если Сеанс.Пользователь.Имя = ИмяПользователя Тогда
            МассивНомеровСеансов.Добавить(Сеанс.НомерСеанса);
        КонецЕсли;
    КонецЦикла;
    
    // Если сеансы найдены, отправляем push-уведомление напрямую в клиентское приложение
    Если МассивНомеровСеансов.Количество() > 0 Тогда
        УведомленияКлиента.ОтправитьУведомление("ВнешнийЗапросHTTP", ДанныеДляПередачи, МассивНомеровСеансов);
    КонецЕсли;
    
КонецПроцедуры

Плюсы: революционный инструмент, не требующий стороннего ПО или Сервера взаимодействия. Работает «из коробки» на уровне платформы.

Минусы: требуется обновление платформы до версии не ниже 8.3.26. При переходе на новые релизы для регулярного обслуживания систем удобно использовать инструмент для автоматического обновления и тестирования баз 1С.

Вариант 4. Встроенный клиент WebSocket (Начиная с версии 8.3.27)

Разберем еще один сценарий. Что если внешнее событие генерируется вашим веб-сервером (например, на Node.js или Python), и вы хотите, чтобы клиентское приложение 1С самостоятельно держало постоянный дуплексный канал связи с этим внешним источником, минуя HTTP-сервисы самой 1С?

Начиная с версии платформы 8.3.27, в 1С появился нативный клиент WebSocket. Теперь нет необходимости использовать интеграцию через поле HTML-документа или внешние компоненты. Для удобного администрирования и мониторинга открытых сессий пригодится инструмент для управления WebSocket-соединениями.

Проанализируем пример подключения к внешнему сокет-серверу прямо из клиента 1С:


// Клиентский код
Перем Сокет;

Процедура ПодключитьWebSocket() Экспорт
    // Инициализируем соединение с внешним сервером уведомлений
    Сокет = Новый WebSocket("ws://192.168.1.100:8080/events");
    
    // Описываем обработчики событий сокета
    ДобавитьОбработчик(Сокет.ПриПолученииСообщения, "ПриПолученииСообщенияОтСокета");
    ДобавитьОбработчик(Сокет.ПриОшибке, "ПриОшибкеСокета");
    
    Сокет.Подключить();
КонецПроцедуры

Процедура ПриПолученииСообщенияОтСокета(Сообщение) Экспорт
    // Обрабатываем сообщение, пришедшее из внешнего веб-сервера напрямую
    ТекстСообщения = Сообщение.ПолучитьТекст();
    ВыполнитьАлгоритмОповещения(ТекстСообщения);
КонецПроцедуры

Плюсы: прямое взаимодействие со сторонним ПО в реальном времени, высокая скорость работы, независимость от HTTP-сервисов 1С.

Минусы: требуется версия платформы 8.3.27 и выше, а также развернутый внешний WebSocket-сервер.

Резюме: какой метод выбрать для проекта?

Выбор оптимального архитектурного решения зависит от используемой версии платформы 1С и требований к инфраструктуре:

← На главную