Как привязать сообщения фонового задания к конкретной форме в 1С

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

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

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

Выясним причину поведения платформы

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

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

Способ 1. Адресация через ИдентификаторНазначения

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

  1. При запуске фонового задания передаем в фоновую процедуру уникальный идентификатор нашей формы: ЭтаФорма.УникальныйИдентификатор.
  2. Внутри исполняемого кода фонового задания отказываемся от простого вызова Сообщить() в пользу создания полноценного объекта СообщениеПользователю.
  3. Присваиваем свойству ИдентификаторНазначения переданный идентификатор формы.

Посмотрим на пример кода на стороне фонового задания:


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

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

Способ 2. Адресный перехват сообщений задания через ПолучитьСообщенияПользователю

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

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

Разберем по шагам программную реализацию в форме с использованием обработчика ожидания:


&НаКлиенте
Процедура ЗапуститьОбработку(Команда)
    ИдентификаторЗадания = ЗапуститьЗаданиеНаСервере();
    ПодключитьОбработчикОжидания("ПроверитьЗадание", 2);
КонецПроцедуры

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

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

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

Способ 3. Передача лога через Временное хранилище

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

В этом сценарии наиболее производительным решением является отказ от системных сообщений в пользу накопления информации во временном хранилище:

  1. Перед запуском фонового задания создаем адрес во временном хранилище на клиенте или сервере: АдресХранилища = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);.
  2. Передаем этот адрес в параметры задания.
  3. Внутри фонового процесса накапливаем лог в коллекции (например, в массиве структур или таблице значений) и периодически (либо по завершении) обновляем данные через ПоместитьВоВременноеХранилище(Коллекция, АдресХранилища);.
  4. В обработчике ожидания формы считываем данные методом ПолучитьИзВременногоХранилища(АдресХранилища) и заполняем элементы формы.

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

← На главную