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

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

В разработке крупных корпоративных систем часто возникает задача мгновенной передачи информации с сервера на сторону клиента (так называемая push-технология). Примерами таких задач могут служить интеграция с SIP-телефонией (когда карточка входящего звонка должна открыться у оператора в ту же секунду), оперативное оповещение о согласовании документов или отображение прогресса длительных фоновых операций на сервере.

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

Почему классический периодический опрос (Polling) — это плохо?

Большинство разработчиков для решения задачи оповещения используют метод ПодключитьОбработчикОжидания на клиенте. С заданной периодичностью (например, каждые 3–5 секунд) клиент обращается к серверу, опрашивая определенный регистр сведений или таблицу задач на предмет появления новых записей. Рассмотрим подробнее, к каким проблемам это приводит при росте информационной базы:

  1. Паразитная нагрузка на сервер СУБД. Если в базе одновременно работают 500 активных пользователей, и у каждого настроен опрос раз в 2 секунды, сервер будет вынужден обрабатывать 250 холостых запросов в секунду. Это приводит к бессмысленному расходу процессорного времени сервера приложений и СУБД.
  2. Задержка (Latency). Если событие произошло на сервере сразу после очередного опроса, клиент узнает о нем только при следующем цикле таймера (через 2–5 секунд). Для критически важных бизнес-процессов (например, биржевая торговля или прием звонков оператором колл-центра) такая задержка недопустима.
  3. Блокировки данных. Постоянное чтение оперативных таблиц множеством сеансов повышает вероятность возникновения взаимных блокировок (deadlocks) и замедляет запись реальных документов другими пользователями.

Развенчание мифов: почему другие "простые" методы не работают

В процессе обсуждения на форумах часто всплывают ошибочные мнения о существовании простых "нативных" альтернатив. Проанализируем самые популярные заблуждения:

Ниже мы подробно разберем три архитектурных решения проблемы: революционное нативное решение в версии 8.3.26 и два проверенных временем обходных пути для более ранних версий платформы.

---

Решение 1. Полностью нативный механизм «Уведомления клиента» в 1С 8.3.26

Начиная с версии платформы 1С:Предприятие 8.3.26, разработчики добавили встроенный и абсолютно бесплатный инструмент — Менеджер уведомлений клиента. Этот механизм работает напрямую через сетевой протокол без использования Системы взаимодействия, не требует покупки КОРП-лицензий и доступен на стандартных ПРОФ-тарифах. Он позволяет серверным процедурам отправлять точечные push-уведомления в конкретные сеансы пользователей.

Рассмотрим, как реализовать этот механизм по шагам.

Шаг 1. Регистрация обработчика на клиенте

При запуске клиентского приложения (например, в модуле управляемого приложения или при открытии ключевой формы) нам необходимо зарегистрировать обработчик, который будет "слушать" серверные события. Для этого используется свойство глобального контекста УведомленияКлиента.


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

&НаКлиенте
Процедура ОбработатьСерверноеУведомление(ДанныеУведомления, ДополнительныеПараметры) Экспорт
    
    // ДанныеУведомления — это структура или объект произвольного типа, переданный с сервера
    ПоказатьОповещениеПользователя("Внимание!", , ДанныеУведомления.ТекстСообщения);
    
    // Здесь можно выполнить любые клиентские действия, например, открыть форму документа
    Если ДанныеУведомления.Свойство("СсылкаНаДокумент") Тогда
        ПоказатьЗначение(, ДанныеУведомления.СсылкаНаДокумент);
    КонецЕсли;
    
КонецПроцедуры

Шаг 2. Отправка уведомления с сервера

На сервере (в обработчике проведения документа, модуле бизнес-процесса или регламентном задании) мы определяем список адресатов и отправляем им данные. Платформа идентифицирует получателей по номерам их сеансов.


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

Преимущество работы из фоновых заданий

В версии 8.3.26 у объекта ФоновоеЗадание появилось новое системное свойство НомерРодительскогоСеанса. Это позволяет длительным фоновым расчетам точечно слать уведомления о проценте выполнения задачи прямо в тот клиентский сеанс, который запустил эту операцию, гарантируя мгновенную обратную связь без перегрузки базы данных запросами. Для организации контроля длительных операций на предыдущих версиях платформы можно использовать пример отслеживания прогресса фоновых заданий без БСП.

---

Решение 2. Обходной путь для старых платформ: Long Polling через HTTP-сервисы

Если ваша информационная база работает на версии платформы ниже 8.3.26, а использовать Систему взаимодействия нет возможности, отличной альтернативой стандартному опросу станет концепция Long Polling (длинные запросы).

При обычном опросе клиент шлет частые запросы и сразу получает ответ (пустой или с данными). При Long Polling клиент отправляет запрос, а сервер намеренно удерживает соединение открытым до тех пор, пока на сервере не произойдет нужное событие (или не истечет таймаут, например, 30 секунд). Только тогда сервер возвращает ответ, а клиент, обработав его, сразу же открывает новое "длинное" соединение.

Рассмотрим схему реализации этого подхода через публикацию собственного HTTP-сервиса 1С.

Реализация на сервере (обработчик HTTP-сервиса 1С):

Создадим HTTP-сервис PushService с шаблоном пути /wait/{ИмяПользователя}.


Функция waitGet(Запрос)
    
    ИмяПользователя = Запрос.ПараметрыШаблона.Получить("ИмяПользователя");
    ВремяНачала = ТекущаяУниверсальнаяДатаВМиллисекундах();
    ТаймаутОжидания = 25000; // Удерживаем соединение максимум 25 секунд
    ЕстьДанные = Ложь;
    Результат = "";
    
    Пока (ТекущаяУниверсальнаяДатаВМиллисекундах() - ВремяНачала) < ТаймаутОжидания Цикл
        
        // Проверяем наличие событий в быстром источнике (например, во временной таблице в ОЗУ или РС)
        События = ПроверитьНовыеСобытияДляПользователя(ИмяПользователя);
        Если События.Количество() > 0 Тогда
            ЕстьДанные = Истина;
            Результат = СформироватьJSONДанных(События);
            Прервать;
        КонецЕсли;
        
        // Приостанавливаем поток на сервере на 1 секунду, чтобы не грузить процессор циклом
        ТекущийСистемныйИнструмент.Пауза(1); 
        
    КонецЦикла;
    
    Ответ = Новый HTTPСервисОтвет(?(ЕстьДанные, 200, 204)); // 204 No Content, если ничего не произошло
    Если ЕстьДанные Тогда
        Ответ.УстановитьТелоИзСтроки(Результат);
    КонецЕсли;
    
    Возврат Ответ;
    
КонецФункции

Реализация на клиенте:

На стороне клиента мы запускаем асинхронный процесс, который вызывает данный HTTP-сервис в фоновом режиме. Как только приходит ответ (код 200), мы обрабатываем его и сразу же рекурсивно инициируем следующий запрос.

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

---

Решение 3. Асинхронные WebSockets через Поле HTML-документа

Еще один продвинутый способ реализации мгновенных уведомлений на старых платформах — использование встроенного в тонкий клиент движка WebKit через Поле HTML-документа. Сама платформа 1С до версии 8.3.26 не умеет работать со стандартными веб-сокетами напрямую, но это отлично делает JavaScript внутри HTML-поля. Для прямого взаимодействия с сокетами без браузерного поля можно использовать внешнюю компоненту WebSocket-клиента.

Схема взаимодействия выглядит следующим образом:

  1. В панели открытого приложения или на главной форме размещается невидимое поле HTML-документа.
  2. При открытии формы в это поле загружается простая HTML-страница со скриптом, который открывает WebSocket-соединение с внешним легким push-сервером (например, написанным на Node.js или использованием бесплатного стороннего сервиса центрифуги сообщений).
  3. Когда на сервере 1С происходит событие, сервер отправляет быстрый HTTP POST запрос на этот внешний push-сервер.
  4. Push-сервер мгновенно транслирует это сообщение по открытому веб-сокету обратно в JS-код, выполняющийся в поле HTML-документа 1С.
  5. JavaScript принимает сообщение и передает его во встроенный язык 1С с помощью встроенного механизма взаимодействия с платформой.

Рассмотрим пример реализации JavaScript-кода, загружаемого в Поле HTML-документа:


<html>
<head>
<script type="text/javascript">
    var socket;
    function connect() {
        // Подключаемся к локальному или внешнему веб-сокет серверу
        socket = new WebSocket("ws://broker.local:8080/notifications");
        
        socket.onmessage = function(event) {
            var messageData = JSON.parse(event.data);
            
            // Передаем данные обратно в платформу 1С
            // Используем штатный механизм интеграции JS и 1С
            if (typeof window.1cConnector !== 'undefined') {
                window.1cConnector.postMessage(JSON.stringify(messageData));
            }
        };
        
        socket.onclose = function(e) {
            // В случае обрыва связи пробуем переподключиться через 5 секунд
            setTimeout(function() { connect(); }, 5000);
        };
    }
    window.onload = connect;
</script>
</head>
<body style="margin:0; padding:0; overflow:hidden;"></body>
</html>

В самой форме 1С достаточно обрабатывать событие поля HTML-документа ПриНажатии или событие получения сообщения от JS-коннектора (в зависимости от используемой версии платформы). Этот метод обеспечивает фантастическую скорость доставки (менее 50 миллисекунд) и не нагружает сервер 1С фоновыми процессами ожидания.

---

Сравнительный анализ решений

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

  1. Менеджер уведомлений клиента (Платформа 8.3.26+):
    • Сложность реализации: Минимальная (штатные методы встроенного языка).
    • Надежность: Максимальная (гарантированная доставка платформой, автоматическое сохранение очереди сообщений при кратковременной потере связи).
    • Нагрузка на сервер: Практически отсутствует.
    • Дополнительное ПО: Не требуется.
  2. Long Polling через HTTP-сервисы (Любая платформа 8.3):
    • Сложность реализации: Средняя.
    • Надежность: Высокая, но требует тонкой настройки пула соединений веб-сервера (IIS/Apache) и лимитов сеансов rphost, так как "висящие" HTTP-запросы занимают рабочие потоки.
    • Нагрузка на сервер: Средняя (зависит от количества удерживаемых соединений).
    • Дополнительное ПО: Не требуется.
  3. WebSockets через HTML-поле (Любая платформа 8.3):
    • Сложность реализации: Высокая (требуется знание JavaScript и HTML).
    • Надежность: Высокая при качественной обработке переподключений в JS.
    • Нагрузка на сервер: Нулевая для 1С (вся нагрузка по удержанию соединений ложится на внешний легковесный веб-сокет брокер).
    • Дополнительное ПО: Требуется сторонний WebSocket-сервер.

Подведем итог: если у вас есть техническая возможность обновить платформу до актуального релиза 8.3.26 — обязательно сделайте это. Новый объект МенеджерУведомленийКлиента полностью закрывает давний пробел в архитектуре 1С, позволяя раз и навсегда отказаться от "костылей" с периодическими обработчиками ожидания. В случае работы на более старых версиях платформы отдавайте предпочтение связке Long Polling или интеграции через Поле HTML-документа, сохраняя производительность СУБД на высоком уровне.

← На главную