Как вызвать клиентскую процедуру после выполнения серверной подписки на событие проведения документа?

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

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

Рассмотрим подробнее, как обойти это ограничение и реализовать передачу сигнала с сервера на клиент, используя современные инструменты платформы и приемы из типовых конфигураций.

Метод 1. Использование Системы взаимодействия

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

Разберем реализацию по шагам:

  1. На стороне сервера (в подписке на событие): нам необходимо сформировать сообщение и отправить его адресату. Для этого используется объект СистемаВзаимодействия.

// Пример кода в серверной подписке
Процедура ПослеПроведенияНаСервере(Источник, Отказ, РежимПроведения) Экспорт
    
    // Определяем получателя (например, текущий пользователь или автор документа)
    НужныйПользователь = Источник.Автор; 
    ИдентификаторПользователя = СистемаВзаимодействия.ПолучитьИдентификаторПользователя(НужныйПользователь.ИдентификаторПользователяИБ);
    
    // Создаем сообщение
    НовоеСообщение = СистемаВзаимодействия.СоздатьСообщение(СистемаВзаимодействия.ПолучитьОбсуждениеПоУмолчанию());
    НовоеСообщение.Текст = "Документ " + Строка(Источник) + " успешно проведен!";
    
    // Можно передать структуру с данными для обработки на клиенте
    ДанныеДляКлиента = Новый Структура;
    ДанныеДляКлиента.Вставить("Событие", "ДокументПроведен");
    ДанныеДляКлиента.Вставить("Ссылка", Источник.Ссылка);
    
    НовоеСообщение.Данные = ДанныеДляКлиента;
    НовоеСообщение.Получатели.Добавить(ИдентификаторПользователя);
    НовоеСообщение.Записать();
    
КонецПроцедуры
  1. На стороне клиента: в модуле управляемого приложения или в коде конкретной формы необходимо подключить обработчик получения сообщения.

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

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

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

Метод 2. Механизм опроса сервера (Polling) через регистр сведений

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

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

  1. Создадим непериодический регистр сведений ОчередьОповещений с измерениями Пользователь (тип СправочникСсылка.Пользователи) и ИдентификаторЗаписи (тип УникальныйИдентификатор), и ресурсом ДанныеОповещения (тип ХранилищеЗначения).
  2. В подписке на событие (Сервер): записываем данные в этот регистр.

МенеджерЗаписи = РегистрыСведений.ОчередьОповещений.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Пользователь = ПараметрыСеанса.ТекущийПользователь;
МенеджерЗаписи.ИдентификаторЗаписи = Новый УникальныйИдентификатор();
МенеджерЗаписи.ДанныеОповещения = Новый ХранилищеЗначения("ОбновитьДанные");
МенеджерЗаписи.Записать();
  1. На стороне клиента: используем метод ПодключитьОбработчикОжидания.

Рассмотрим пример настройки в модуле управляемого приложения или форме рабочего стола:


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

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

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

Метод 3. Использование подсистем БСП (Напоминания и Текущие дела)

Посмотрим на ситуацию со стороны типовых решений, таких как УНФ или ERP. В них уже внедрена Библиотека стандартных подсистем (БСП), которая содержит готовые механизмы для уведомлений.

Например, подсистема НапоминанияПользователя. Мы можем программно создать напоминание для текущего пользователя, которое должно сработать "сейчас".


// Пример использования БСП для создания немедленного напоминания
Напоминание = РегистрыСведений.НапоминанияПользователя.СоздатьМенеджерЗаписи();
Напоминание.Пользователь = ПараметрыСеанса.ТекущийПользователь;
Напоминание.ВремяСобытия = ТекущаяДатаСеанса();
Напоминание.СпособУстановкиВремени = Перечисления.СпособыУстановкиВремениНапоминания.В指定Время;
Напоминание.Текст = "Документ проведен, обновите данные.";
Напоминание.Источник = Источник.Ссылка;
Напоминание.Записать();

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

Разбор примера с «Дашей» в УНФ

В сообщениях форума упоминался ассистент управления «Даша» в УНФ. Проанализируем, как это устроено. По сути, это комбинация методов: событие (проведение) регистрируется в специальной таблице задач (очереди), а на клиенте работает фоновый процесс или периодический опрос этой очереди. Как только «Даша» видит выполненную задачу на сервере, она инициирует визуальное изменение на рабочем столе пользователя.

Ограничения фоновых заданий

Важно понимать: ФоновоеЗадание всегда выполняется на сервере. Оно не имеет доступа к Окно, Форма или методу Оповестить. Фоновое задание может только подготовить данные в базе. Чтобы эти данные "всплыли" на клиенте, нам все равно придется использовать либо Систему взаимодействия, либо Обработчик ожидания.

Итог: что выбрать?

Выясним причины выбора того или иного метода:

Таким образом, прямой вызов Оповестить из серверной подписки невозможен, но используя один из описанных "мостов", мы можем эффективно передать управление на сторону клиента.

← На главную