Как реализовать кнопку "Отмена" для длительной обработки на сервере во внешней обработке?

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

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

В этой статье мы подробно разберем, как перенести выполнение кода внешней обработки в фоновое задание и реализовать кнопку "Отмена", используя механизмы платформы и Библиотеки Стандартных Подсистем (БСП).

Почему нельзя просто добавить кнопку "Отмена"?

Давайте разберемся в архитектуре. Когда выполняется серверный вызов, клиентское приложение ожидает ответа от сервера. Пока сервер не вернет управление, клиент "молчит". Единственный способ оставить интерфейс отзывчивым — запустить вычисления в отдельном потоке, то есть в фоновом задании.

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

Использование механизма "Длительные операции" (БСП)

В современных конфигурациях (ERP, УТ 11, КА, БП 3.0) внедрена подсистема ДлительныеОперации. Она берет на себя самую сложную часть работы:

  1. Запуск фонового задания.
  2. Отображение окна ожидания (прогресс-бара).
  3. Реализацию кнопки "Отмена".
  4. Корректную передачу контекста внешней обработки.

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

Подготовка параметров запуска

Поскольку фоновое задание не "видит" код нашей обработки напрямую, мы должны использовать специальную процедуру-обертку из БСП. Обычно она называется ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки (имя может отличаться в зависимости от версии БСП, но суть остается прежней).

Разберем код подготовки задания, основанный на примере из обсуждения:


// 1. Находим ссылку на нашу дополнительную обработку в справочнике
ДополнительнаяОбработкаСсылка = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("Загрузить заказы из файла Excel");

// 2. Указываем метод-обертку БСП, который умеет работать с внешними обработками
ВыполняемыйМетод = "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки";

// 3. Формируем структуру параметров для этой обертки
ПараметрыЗадания = Новый Структура;

// Имя внешней обработки, как она задана в метаданных файла
ПараметрыЗадания.Вставить("ИмяОбработки", "ВнешняяОбработка.ЗагрузкаЗаказовПоставщикамИзФайла");

// Имя Экспортной процедуры в модуле объекта вашей обработки, которую нужно выполнить
ПараметрыЗадания.Вставить("ИмяМетода", "ВыполнитьЗагрузкуНаСервере"); 

// Указываем, что это именно внешняя обработка
ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", Истина);

// Ссылка на элемент справочника, чтобы БСП могла найти файл обработки в базе
ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка", ДополнительнаяОбработкаСсылка);

Обратите внимание на параметр ИмяМетода. В вашей внешней обработке в модуле объекта должна быть процедура с таким именем и ключевым словом Экспорт.

Запуск задания и обработка отмены

Далее нам необходимо подготовить параметры выполнения и запустить процесс. БСП предоставляет удобные структуры для этого.


// Подготовка параметров выполнения
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = "Загрузка заказов поставщику";
ПараметрыВыполнения.ЗапуститьВФоне = Истина;

// Запуск фонового задания
СтруктураФоновогоЗадания = ДлительныеОперации.ВыполнитьВФоне(ВыполняемыйМетод, ПараметрыЗадания, ПараметрыВыполнения);

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

В клиентском коде (в модуле формы) это выглядит примерно так:


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

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

Как происходит отмена задания?

Когда пользователь нажимает "Отмена", происходит вызов метода ФоновоеЗадание.Отменить(). Это приводит к принудительному завершению работы фонового процесса на сервере.

Давайте рассмотрим два сценария отмены:

1. Жесткая отмена (по умолчанию)

Если вы ничего не предпринимаете в коде, нажатие кнопки "Отмена" просто "убьет" фоновое задание. Если в этот момент шла запись данных:

2. Мягкая отмена (рекомендуемый подход)

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

Пример кода внутри вашей экспортной процедуры обработки:


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

КонецПроцедуры

Важные ограничения

При реализации данного механизма помните о следующих моментах:

  1. Сериализация: Вы не можете передать в параметры задания (переменная ПараметрыЗадания) сложные объекты, такие как УправляемаяФорма или ТаблицаЗначений. Если нужно передать таблицу, поместите её во ВременноеХранилище и передайте адрес (строку). Внутри фонового задания получите данные по адресу.
  2. Отладка: Отладка фоновых заданий требует включения соответствующего режима в настройках сервера 1С или использования файловой базы. По умолчанию точки останова в фоне могут не срабатывать.
  3. Регистрация: Метод, описанный выше, лучше всего работает, если внешняя обработка зарегистрирована в базе. Если вы хотите запускать фон из просто открытого файла (Файл -> Открыть), вам придется программно помещать двоичные данные обработки во временное хранилище и передавать адрес, чтобы фоновое задание могло "скачать" и подключить этот код.

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

← На главную