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