Как вызвать ПоказатьОповещениеПользователя из серверного кода &НаСервере в 1С

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

Разработчики часто сталкиваются с ситуацией, когда в процессе выполнения тяжелой серверной процедуры или фонового задания требуется оперативно проинформировать пользователя о завершении процесса или возникновении важного события. Стандартный метод ПоказатьОповещениеПользователя, который выводит красивое всплывающее окошко (тот самый «зеленый колокольчик»), доступен исключительно в клиентском контексте &НаКлиенте. Попытка вызвать его напрямую из процедуры с директивой компиляции &НаСервере или &НаСервереБезКонтекста приведет к синтаксической ошибке на этапе компиляции.

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

Вариант 1. Накопление оповещений на сервере и вывод после возврата на клиент

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

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

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

Посмотрим на практический пример реализации этого подхода:


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

&НаСервереБезКонтекста
Функция ВыполнитьДействиеНаСервере()
    
    СписокОповещений = Новый Массив;
    
    // ... Выполнение сложной бизнес-логики ...
    
    // Если в процессе работы возникло событие, требующее оповещения:
    ДанныеОповещения = Новый Структура;
    ДанныеОповещения.Вставить("Событие", "Успешная загрузка");
    ДанныеОповещения.Вставить("НавигационнаяСсылка", "");
    ДанныеОповещения.Вставить("Текст", "Данные контрагентов успешно обновлены.");
    ДанныеОповещения.Вставить("Картинка", БиблиотекаКартинок.Информация);
    
    СписокОповещений.Добавить(ДанныеОповещения);
    
    Возврат СписокОповещений;
    
КонецФункции

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

Вариант 2. Использование регистра сведений НапоминанияПользователя

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

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

Проанализируем алгоритм реализации этого обходного пути:

  1. В серверном коде мы программно создаем запись в регистре сведений НапоминанияПользователя. В качестве ключевых полей указываем пользователя, время напоминания (текущую дату и время) и текст сообщения.
  2. На стороне клиента в БСП уже работает штатный обработчик ожидания, который с заданной периодичностью проверяет наличие актуальных напоминаний для текущего пользователя.
  3. Чтобы кастомизировать вывод и превратить стандартное окно напоминания во всплывающее оповещение («колокольчик»), мы можем немного доработать форму оповещения этого регистра. В модуле формы ФормаОповещения регистра НапоминанияПользователя при ее открытии мы перехватываем управление, считываем текст напоминания, вызываем метод ПоказатьОповещениеПользователя и сразу же закрываем саму форму, чтобы она не мозолила глаза пользователю.

Этот способ позволяет отправлять оповещения из любого серверного контекста (включая регламентные и фоновые задания) любому активному пользователю базы данных без непосредственной связи клиента и сервера в рамках одного сеанса. Для быстрой организации подобной рассылки можно использовать расширение для срочного оповещения активных пользователей.

Вариант 3. Современный штатный механизм Уведомления клиента

Начиная с версии платформы 1С:Предприятие 8.3.26, фирма 1С реализовала долгожданный штатный механизм отправки уведомлений с сервера на клиент в режиме реального времени. Этот механизм называется УведомленияКлиента и работает без создания паразитной нагрузки на базу данных.

Выясним, как устроен этот механизм и как его правильно настроить:

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

Рассмотрим пример кода для реализации этого современного подхода. Сначала настроим клиентскую часть в модуле управляемого приложения:


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

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

Теперь посмотрим, как отправить уведомление с сервера:


&НаСервере
Процедура ОтправитьОповещениеПользователю(ЦелевойПользователь, ТекстОповещения)
    
    // Формируем структуру с данными для отображения на клиенте
    ПараметрыСообщения = Новый Структура;
    ПараметрыСообщения.Вставить("ТипСобытия", "ВсплывающееОповещение");
    ПараметрыСообщения.Вставить("Заголовок", "Уведомление от системы");
    ПараметрыСообщения.Вставить("Текст", ТекстОповещения);
    ПараметрыСообщения.Вставить("Ссылка", "");
    
    // Находим активные сеансы нужного пользователя
    МассивСеансов = ПолучитьСеансыПользователя(ЦелевойПользователь);
    
    // Отправляем уведомление на клиенты
    УведомленияКлиента.ОтправитьУведомление(МассивСеансов, ПараметрыСообщения);
    
КонецПроцедуры

Этот способ является наиболее производительным, надежным и архитектурно правильным в современных версиях платформы 1С.

Вариант 4. Система взаимодействия как шина мгновенных сообщений

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

Разберем по шагам логику этого подхода:

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

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

Вариант 5. Опрос сервера через обработчик ожидания

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

Давайте проанализируем схему реализации данного механизма:

  1. Создание очереди сообщений: В конфигурации создается простейший регистр сведений (например, ОчередьОповещенийПользователей) с измерениями Пользователь и ИдентификаторЗаписи, и ресурсами Заголовок, Текст.
  2. Запись на сервере: Любая серверная процедура, которой нужно вывести оповещение на клиенте, просто делает запись в этот регистр сведений, указывая адресатом конкретного пользователя.
  3. Опрос на клиенте: При старте системы запускается периодический фоновый опрос сервера с помощью метода ПодключитьОбработчикОжидания() с интервалом, например, в 10–15 секунд.
  4. Обработка на клиенте: Клиентская процедура обращается к серверной функции, которая проверяет наличие записей в регистре для текущего пользователя. Если записи найдены, они считываются, удаляются из регистра (чтобы не обрабатывать их повторно), возвращаются на клиент и выводятся пользователю через ПоказатьОповещениеПользователя.

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


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

&НаКлиенте
Процедура ПроверитьОчередьОповещений() Экспорт
    
    НовыеОповещения = ПолучитьОповещенияИзОчередиНаСервере();
    
    Для Каждого Оповещение Из НовыеОповещения Цикл
        ПоказатьОповещениеПользователя(
            Оповещение.Заголовок,
            Оповещение.Ссылка,
            Оповещение.Текст
        );
    КонецЦикла;
    
КонецПроцедуры

Серверная часть для получения и очистки очереди:


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

Основным минусом данного метода является постоянная нагрузка на сервер СУБД из-за регулярных запросов от всех активных пользователей. Поэтому интервал опроса не рекомендуется делать слишком маленьким.

Вариант 6. Длительные операции БСП при работе с фоновыми заданиями

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

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

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

← На главную