Как вызвать клиентский код или открыть форму из серверного общего модуля или регламентного задания

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

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

Почему сервер «не видит» клиента: основы архитектуры

Для начала проанализируем ситуацию с точки зрения архитектуры системы. В 1С реализована строгая иерархия вызовов: Клиент может обращаться к Серверу, но Сервер никогда не может быть инициатором обращения к Клиенту. Это связано с тем, что клиентское приложение (тонкий, толстый или веб-клиент) является активным потребителем ресурсов сервера, в то время как сервер — это пассивный исполнитель запросов.

Ситуация усложняется, когда код исполняется в рамках регламентного задания. Рассмотрим подробнее: регламентное задание запускается в отдельном сеансе на сервере приложений. У этого сеанса вообще нет пользовательского интерфейса. Даже если бы теоретическая возможность «достучаться» до клиента существовала, сервер не знал бы, кому именно из сотен подключенных пользователей нужно открыть форму.

Решение 1: Правильная структуризация кода и перенос логики

Первый и самый правильный метод — это рефакторинг. Если вам нужно вызвать процедуру из общего модуля, которая помечена как Клиент, следует выяснить, действительно ли в ней используются специфические клиентские методы (например, Предупреждение() или ОткрытьФорму()).

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

Разберем по шагам, как изменить свойства модуля:

  1. Найдем нужный общий модуль в дереве метаданных.
  2. В палитре свойств установим флажки Сервер и Клиент (управляемое приложение).
  3. Убедимся, что внутри модуля не используются методы, доступные только на клиенте, либо обрамим их инструкциями препроцессора:

#Если Клиент Тогда
    Оповестить("Данные обработаны");
#КонецЕсли

Решение 2: Метод опроса (Pull-модель) через обработчик ожидания

Если нам все же необходимо, чтобы сервер «подал сигнал» клиенту, воспользуемся проверенным методом с использованием регистра сведений или константы. Суть метода заключается в том, что сервер записывает задачу в базу данных, а клиент периодически проверяет наличие новых задач.

Выясним причину популярности этого метода: он работает во всех версиях 1С 8 и не требует сложной настройки. Реализуем его по шагам:

Шаг 1. Создание «Очереди событий». Создадим регистр сведений ОчередьСобытийДляКлиента с измерениями Пользователь и ресурсом ПараметрыСобытия (тип Строка или ХранилищеЗначения).

Шаг 2. Запись события на сервере. В серверном модуле или регламентном задании добавим код записи:


НоваяЗапись = РегистрыСведений.ОчередьСобытийДляКлиента.СоздатьМенеджерЗаписи();
НоваяЗапись.Пользователь = НужныйПользователь;
НоваяЗапись.ПараметрыСобытия = "ОТКРЫТЬ_ФОРМУ_ДОКУМЕНТА";
НоваяЗапись.Записать();

Шаг 3. Проверка на клиенте. В модуле управляемого приложения (или в форме, которая всегда открыта) настроим ПодключитьОбработчикОжидания.


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

&НаКлиенте
Процедура ПроверитьНаличиеСобытийСервера()
    // Вызов серверной функции, которая проверяет записи в регистре
    Параметры = ПроверитьОчередьНаСервере(); 
    Если Параметры <> Неопределено Тогда
        // Выполняем клиентское действие, например:
        ОткрытьФорму("Документ.РеализацияТоваровУслуг.ФормаОбъекта");
    КонецЕсли;
КонецПроцедуры

Решение 3: Система взаимодействия (Push-модель)

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

Проанализируем преимущества: сообщение доставляется почти мгновенно (через WebSocket), и клиент реагирует на него сразу. Для этого на стороне клиента должен быть установлен обработчик оповещений системы взаимодействия.

Пример отправки сигнала с сервера:


ВыбранныйПользователь = ПользователиИнформационнойБазы.НайтиПоИмени("ИвановИИ");
Обсуждение = СистемаВзаимодействия.СоздатьОбсуждение();
Обсуждение.Участники.Добавить(ВыбранныйПользователь);
Обсуждение.Записать();

Сообщение = СистемаВзаимодействия.СоздатьСообщение(Обсуждение.Идентификатор);
Сообщение.Текст = "Команда:ОткрытьФорму";
Сообщение.Записать();

На стороне клиента в коде инициализации системы взаимодействия мы перехватываем это сообщение и выполняем нужный ОткрытьФорму или другой клиентский метод.

Решение 4: Работа с внешними событиями

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

Подведение итогов

Рассмотрев все варианты, мы видим, что «обойти» архитектуру напрямую невозможно, но можно использовать обходные пути в зависимости от версии платформы и бизнес-задачи:

  1. Для простых расчетов: Меняем область видимости модуля (флаги Сервер, Клиент).
  2. Для гарантированной доставки сигнала (старый метод): Используем регистр сведений и ПодключитьОбработчикОжидания.
  3. Для современных систем: Используем Систему взаимодействия для мгновенных Push-уведомлений.

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

← На главную