При разработке на платформе 1С:Предприятие часто возникает задача вынести ресурсоемкие операции, такие как проведение документов или сложные расчеты, в фоновое задание. Если код находится в основной конфигурации, проблем не возникает. Однако, когда логика размещена во внешней обработке (.epf), программист сталкивается с техническим барьером: фоновое задание запускается в новом сеансе на сервере, который "не знает" о существовании объекта внешней обработки, открытого в текущем сеансе пользователя. В этой статье мы подробно разберем, как преодолеть это ограничение, используя возможности БСП и стандартные механизмы платформы.
Прежде чем перейти к решениям, проанализируем причину проблемы. Когда мы запускаем фоновое задание через ФоновыеЗадания.Выполнить() или ДлительныеОперации.ВыполнитьВФоне(), система создает абсолютно чистый серверный сеанс. Объект ВнешняяОбработкаОбъект, который создан у пользователя в памяти, не может быть передан в этот сеанс, так как он не является сериализуемым. Фоновое задание не имеет доступа к файловой системе клиентского компьютера и не может самостоятельно "прочитать" ту же обработку, если она не сохранена в базе или в доступном серверу сетевом ресурсе.
Рассмотрим два основных сценария решения этой задачи в зависимости от того, как используется обработка в вашей системе.
Если ваша внешняя обработка подключена к информационной базе стандартным способом (через справочник Дополнительные отчеты и обработки), то задача значительно упрощается. Библиотека стандартных подсистем (БСП) уже содержит готовый механизм для таких случаев.
Разберем алгоритм действий:
ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения).ДополнительныеОтчетыИОбработкиКлиент.ВыполнитьКомандуВФоне().Посмотрим на пример кода, который инициирует запуск:
ПараметрыВыполнения = ДополнительныеОтчетыИОбработкиКлиент.ПараметрыВыполненияКомандыВФоне(ВладелецФормы);
ПараметрыВыполнения.СообщениеОДлительнойОперации = "Выполняется проведение, подождите...";
ДополнительныеОтчетыИОбработкиКлиент.ВыполнитьКомандуВФоне(СсылкаНаОбработку, "ИмяКоманды", ПараметрыВыполнения);
В этом случае БСП сама извлечет двоичные данные обработки из справочника, создаст временный сеанс на сервере, подключит обработку и вызовет нужный метод. Это самый надежный и "правильный" путь для конфигураций на БСП.
Если же ваша обработка запускается как файл (через Файл - Открыть) и не зарегистрирована в базе, нам придется реализовать механизм передачи данных вручную. Основная идея заключается в том, чтобы передать двоичные данные файла .epf в фоновое задание через Временное хранилище.
Рассмотрим пошагово, как это реализовать:
Шаг 1. Подготовка данных на стороне инициатора. Мы должны прочитать файл обработки в двоичные данные и поместить их в хранилище, адрес которого передадим в фоновое задание.
// На клиенте или сервере
ДвоичныеДанныеОбработки = Новый ДвоичныеДанные(ПутьКФайлуОбработки);
АдресХранилища = ПоместитьВоВременноеХранилище(ДвоичныеДанныеОбработки, Новый УникальныйИдентификатор);
ПараметрыПроцедуры = Новый Структура;
ПараметрыПроцедуры.Вставить("АдресХранилища", АдресХранилища);
ПараметрыПроцедуры.Вставить("ДополнительныеПараметры", ВашиПараметры);
// Запуск фонового задания через БСП
Результат = ДлительныеОперации.ВыполнитьВФоне("ВашОбщийМодуль.ВыполнитьПроцедуруОбработкиВФоне", ПараметрыПроцедуры);
Шаг 2. Реализация серверного метода-прокладки. В общем модуле (например, ВашОбщийМодуль) необходимо создать экспортную процедуру, которая примет адрес хранилища, создаст объект обработки и запустит целевой метод.
Процедура ВыполнитьПроцедуруОбработкиВФоне(Параметры, АдресРезультата) Экспорт
// Извлекаем данные из хранилища
ДвоичныеДанные = ПолучитьИзВременногоХранилища(Параметры.АдресХранилища);
ИмяФайла = ПолучитьИмяВременногоФайла("epf");
ДвоичныеДанные.Записать(ИмяФайла);
// Создаем объект внешней обработки
// Важно: в безопасном режиме может потребоваться доп. настройка
Попытка
ОбработкаОбъект = ВнешниеОбработки.Создать(ИмяФайла, Ложь);
// Вызываем целевую экспортную процедуру обработки
ОбработкаОбъект.ВашаПроцедураПроведения(Параметры.ДополнительныеПараметры);
Исключение
ЗаписьЖурналаРегистрации("ФоноваяОбработка", УровеньЖурналаРегистрации.Ошибка, , , КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
// Удаляем временный файл
УдалитьФайлы(ИмяФайла);
КонецПроцедуры
Работая с фоновыми заданиями и внешними обработками, необходимо учитывать специфику серверного контекста:
Сообщить() (в старом понимании), Вопрос(), Предупреждение(), ОткрытьФорму(). Если код проведения содержит такие вызовы, фоновое задание завершится с ошибкой. Для передачи сообщений пользователю используйте ОбщегоНазначения.СообщитьПользователю() или механизмы прогресса БСП.ВнешниеОбработки.Создать() вторым параметром передается Ложь (отключение безопасного режима), и у пользователя, под которым запускается фоновое задание, достаточно прав.ПараметрыПроцедуры, должны быть сериализуемыми. Вы можете передать ссылки на справочники, числа, строки, структуры и массивы, но не можете передать, например, открытое соединение с базой данных или COM-объект.Для того чтобы пользователь видел, что происходит в фоне, рекомендуем использовать метод ДлительныеОперации.СообщитьПрогресс(). Выясним, как это работает: внутри процедуры внешней обработки вы можете периодически вызывать этот метод, передавая процент выполнения или текстовое сообщение. Основная форма, запустившая задание, сможет подхватить эти данные через обработчик ожидания и обновить индикатор на экране.
Проанализировав ситуацию, мы видим, что наиболее элегантным решением является встраивание обработки в справочник БСП. Это избавляет от необходимости вручную манипулировать временными файлами и хранилищами, обеспечивая при этом высокий уровень безопасности и стабильности системы.