При разработке чатов, систем информирования или механизмов оперативного обновления данных в 1С часто возникает задача: как сообщить всем подключенным пользователям (клиентским сеансам) о том, что на сервере произошло событие (например, записан документ, обновлен курс валют или пришел запрос через веб-сервис)?
Разберем, почему стандартные клиентские методы не работают для массовой рассылки с сервера, проанализируем ошибки и рассмотрим проверенные архитектурные решения этой задачи.
Метод Оповестить() относится к глобальному контексту клиента. Когда на сервере выполняется код — например, в подписке на событие ПриЗаписи регистра или справочника — серверный код исполняется в контексте сессии конкретного пользователя, который инициировал запись.
Если вызывать процедуру с клиентом из серверного модуля, событие оповещения перехватывается только текущим сеансом этого пользователя. Сервер 1С, фоновые задания, регламентные процедуры и веб-сервисы работают в изолированных сеансах и не имеют прямого доступа к контексту форм и пользовательским интерфейсам других активных сеансов. Поэтому другие пользователи не получат сообщение через Оповестить().
Это классический и универсальный способ, работающий на любых версиях платформы 1С:Предприятие 8.
Суть подходы заключается в следующем: при наступлении события на сервере запись о нем фиксируется в базе данных (например, в регистре сведений), а на клиенте периодически выполняется опрос (polling) этого регистра.
Рассмотрим реализацию по шагам:
ОчередьСобытий:
Процедура ПодпискаПриЗаписиПриЗаписи(Источник, Отказ, Замещение) Экспорт
// Создаем запись в регистре сведений для оповещения пользователей
МенеджерЗаписи = РегистрыСведений.ОчередьСобытий.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ТекущаяУниверсальнаяДата();
МенеджерЗаписи.ИмяСобытия = "ОбновлениеКурсов";
МенеджерЗаписи.Параметр = "КурсыCurrencyОбновлены";
МенеджерЗаписи.Записать();
КонецПроцедуры
ПодключитьОбработчикОжидания():
Процедура ПриНачалеРаботыСистемы()
ПодключитьОбработчикОжидания("ПроверитьНовыеСобытия", 10); // Проверка каждые 10 секунд
КонецПроцедуры
Процедура ПроверитьНовыеСобытия() Экспорт
МассивСобытий = ПроверитьСобытияНаСервере();
Для Каждого Событие Из МассивСобытий Цикл
Оповестить(Событие.ИмяСобытия, Событие.Параметр);
КонецЦикла;
КонецПроцедуры
Достоинства: Простая реализация, работающая на любых версиях платформы.
Недостатки: Создает дополнительную нагрузку на сервер БД при большом количестве активных пользователей.
Платформа 1С содержит встроенную Систему взаимодействия, которая позволяет организовывать обмены сообщениями и push-уведомлениями между сеансами без необходимости постоянных запросов к базе данных.
Проанализируем пример отправки сообщения с сервера:
// На сервере в подписке на событие создаем сообщение в обсуждении
Обсуждение = СистемаВзаимодействия.ПолучитьОбсуждение("ОбщийЧатОповещений");
Сообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
Сообщение.Текст = "Курсы валют успешно обновлены!";
Сообщение.Записать();
На клиенте можно подключить обработчик получения сообщений Системы взаимодействия. Клиентские сеансы будут получать информирование мгновенно в режиме реального времени.
В современных версиях платформы добавлен специализированный механизм push-уведомлений — объект МенеджерУведомленийКлиента (доступен через УведомленияКлиента).
Этот механизм разработан специально для доставки произвольных событий с сервера напрямую на клиенты без использования Системы взаимодействия.
Посмотрим на пример отправки с сервера:
// На сервере отправляем событие всем подключенным сеансам
ДанныеУведомления = Новый Структура("Статус", "Обновлено");
УведомленияКлиента.ОтправитьУведомление("Чат_Обновление", ДанныеУведомления);
На стороне клиента подписываемся на перехват данного события:
Процедура ПриНачалеРаботыСистемы()
УведомленияКлиента.ПодключитьОбработчик("Чат_Обновление", Новый ОписаниеОповещения("ОбработатьСерверноеСобытие", ЭтотОбъект));
КонецПроцедуры
Процедура ОбработатьСерверноеСобытие(ИмяСобытия, Данные, ДополнительныеПараметры) Экспорт
// Выполняем обновление интерфейса или оповещение формы
Оповестить("ОбновитьСообщения");
КонецПроцедуры
Для высоконагруженных систем или задач с требованиями к мгновенной доставке (сотни и тысячи одновременно работающих пользователей) применяют интеграцию с внешними брокерами сообщений (RabbitMQ, Redis) или WebSocket-серверами.
Выяснив ограничения метода Оповестить(), мы видим, что напрямую передать клиентское событие из серверной подписки всем сеансам нельзя. Выбор оптимального решения зависит от версии вашей платформы: