1С БСП. Запуск фонового задания во внешней обработке с индикацией
В данной статье описан пример кода для запуска фонового задания из формы внешней обработки средствами 1С БСП с возможностью отображения индикации.
Contents
Описание используемых процедур
Данный пример кода реализован с использованием функционала Длительных операций 1С:Библиотеки стандартных подсистем версии 2.3.2 и выше.
В 1С БСП существует функционал для запуска фоновых заданий из дополнительных обработок в общем модуле ДлительныеОперации.
Основные процедуры функционала Длительных операций БСП, используемые в данном примере:
— Запуск экспортной функции внешней обработки происходит через функцию ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки, в которую необходимо передать данные для запуска: имя процедуры, ссылка на дополнительную обработку, имя обработки и другие;
— Процедура ДлительныеОперации.ВыполнитьВФоне: Запустить выполнение процедуры в фоновом задании, если это возможно;
— Функция ДлительныеОперации.ПрочитатьПрогресс: Считывает информацию о ходе выполнения фонового задания;
— Функция ДлительныеОперации.СообщитьПрогресс: Регистрирует информацию о ходе выполнения фонового задания;
— Процедура ДлительныеОперацииКлиент.ОжидатьЗавершение: Ожидать завершения выполнение процедуры в фоновом задании и открыть форму ожидания длительной операции.
Со всеми детальными описаниями и параметрами функций и процедур можно ознакомится в комментариях перед соответствующими процедурами в общих модулях.
Рассмотрим пример обработки.
Пример запуска процедуры внешней обработки в фоновом режиме с помощью функционала 1С БСП
В модуле объекта необходимо описать сведения о внешней обработке. Команда будет запускаться через команду формы.
Функция СведенияОВнешнейОбработке() Экспорт
ДанныеДляРег = Новый Структура();
ДанныеДляРег.Вставить("Наименование", "Пример длит. операций во внешней обработке");
ДанныеДляРег.Вставить("БезопасныйРежим", Ложь);
ДанныеДляРег.Вставить("Версия", "ver.: 1");
ДанныеДляРег.Вставить("Информация", "Пример длит. операций во внешней обработке");
ДанныеДляРег.Вставить("Вид", "ДополнительнаяОбработка");
ТабЗнКоманды = Новый ТаблицаЗначений;
ТабЗнКоманды.Колонки.Добавить("Идентификатор");
ТабЗнКоманды.Колонки.Добавить("Использование");
ТабЗнКоманды.Колонки.Добавить("Представление");
НовСтрока = ТабЗнКоманды.Добавить();
НовСтрока.Идентификатор = "ОткрытьОбработку";
НовСтрока.Использование = "ОткрытиеФормы";
НовСтрока.Представление = "Пример длит. операций во внешней обработке";
ДанныеДляРег.Вставить("Команды", ТабЗнКоманды);
Возврат ДанныеДляРег;
КонецФункции
Также вставим экспортную функцию, которая будет запускаться в фоновом задании. В качестве параметров у функции:
— СтруктураПараметров (тип Структура) — параметры, которые мы передали при запуске длительной операции;
— АдресРезультата (тип УникальныйИдентификатор) — Адрес временного хранилища, присвоенный при запуске задания, в котором будут записаны результаты работы процедуры.
В нашем примере на вход передается число — количество итераций, которое задается пользователем.
На выходе получаем массив чисел и помещаем во временное хранилище.
В рамках одного запущенного фонового задания можно отслеживать прогресс выполнения с помощью процедур ДлительныеОперации.СообщитьПрогресс и ДлительныеОперации.ПолучитьПрогресс.
В процедуре выполнения выполняем процедуру ДлительныеОперации.СообщитьПрогресс, которая регистрирует информацию о ходе выполнения фонового задания. Передаем параметры «Процент» и «Текст». Также можно передать структуру с дополнительными параметрами.
Процедура ДлительнаяОперация(СтруктураПараметров, АдресРезультата) Экспорт
МассивВозврат = Новый Массив;
Для Ин = 1 ПО СтруктураПараметров.КоличествоИтераций Цикл
//ваш код
Если Ин/100 - Окр(Ин/100, 0) = 0 Тогда
МассивВозврат.Добавить(Ин);
КонецЕсли;
ТекущийПроцентВыполнения = Окр(100*Ин/СтруктураПараметров.КоличествоИтераций, 0);
ДлительныеОперации.СообщитьПрогресс(ТекущийПроцентВыполнения, СтрШаблон("Выполняется итерация %1", Ин));
КонецЦикла;
ПоместитьВоВременноеХранилище(МассивВозврат, АдресРезультата);
КонецПроцедуры
На форме добавляем команду, при выполнении которой будет запускаться фоновое задание.
&НаКлиенте
Функция ПодготовитьДанныеДляДлительнойОперации()
Возврат Новый Структура("КоличествоИтераций", КоличествоИтераций);
КонецФункции
&НаКлиенте
Процедура ЗапуститьВыполнение(Команда)
//сохраним идентификатор задания в реквизите формы
ИДЗадания = "";
//готовим входящие данные для фоновой процедуры
ПараметрыЗапуска = ПодготовитьДанныеДляДлительнойОперации();
//запускаем фоновое задание, параметры: структура вх. данных и уникальный идентификатор формы-владельца
СтруктураФоновогоЗадания = ВыполнитьФоновоеЗаданиеНаСервере(ПараметрыЗапуска, УникальныйИдентификатор);
ИДЗадания = СтруктураФоновогоЗадания.ИдентификаторЗадания;
//получаем структуру параметров ожидания и устанавливаем необходимые параметры
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
// указываем необходимость вывода окна с индикацией
ПараметрыОжидания.ВыводитьОкноОжидания = Истина;
// указываем необходимость вывода прогресса состояния
ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина;
// указываем интервал обновления состояния в секундах, если не указать,
// то интервал будет увеличиваться при каждой итерации в 1.4 раза.
ПараметрыОжидания.Интервал = 2;
//Ожидать завершения выполнение процедуры в фоновом задании и открыть форму ожидания длительной операции.
ДлительныеОперацииКлиент.ОжидатьЗавершение(
СтруктураФоновогоЗадания,
Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект),
ПараметрыОжидания);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ВыполнитьФоновоеЗаданиеНаСервере(ПараметрыЗапуска, УникальныйИдентификатор)
НаименованиеЗадания = НСтр("ru = 'Запуск длительной операции'");
//ссылка на доп. обработку, подключенную к базе. В данном примере ищем по наименованию, указанному в Сведениях о внешней обработке
ДополнительнаяОбработкаСсылка = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("Пример длит. операций во внешней обработке");
//запуск фоновой процедуры происходит через метод "ВыполнитьПроцедуруМодуляОбъектаОбработки", куда мы передаем данные об обработке и о процедуре, которую необходимо запустить
ВыполняемыйМетод = "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки";
ПараметрыЗадания = Новый Структура;
//имя внешней обработки
ПараметрыЗадания.Вставить("ИмяОбработки", "ВнешняяОбработка.ДлительныеОперацииВоВнешнейОбработке");
//имя экспортной серверной процедуры обработки
ПараметрыЗадания.Вставить("ИмяМетода", "ДлительнаяОперация");
//входящие параметры процедуры
ПараметрыЗадания.Вставить("ПараметрыВыполнения", ПараметрыЗапуска);
//признак внешней обработки
ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", Истина);
//ссылка на доп. обработку в базе
ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка",ДополнительнаяОбработкаСсылка);
//получаем пустую структуру параметров выполнения фонового задания и заполняем ее необходимыми данными
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = НаименованиеЗадания;
ПараметрыВыполнения.ЗапуститьВФоне = Истина;
ПараметрыВыполнения.Вставить("ИдентификаторФормы", УникальныйИдентификатор);
//запускаем выполнение фонового задания
СтруктураФоновогоЗадания = ДлительныеОперации.ВыполнитьВФоне(ВыполняемыйМетод, ПараметрыЗадания, ПараметрыВыполнения);
Возврат СтруктураФоновогоЗадания;
КонецФункции
&НаКлиенте
Процедура ОбработатьДанные(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат;
ИначеЕсли Результат.Статус = "Ошибка" Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(Результат.ПодробноеПредставлениеОшибки);
ИначеЕсли Результат.Статус = "Выполнено" Тогда
// обрабатываем результат
Данные = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
ВозвратноеЗначение = Данные.Количество();
КонецЕсли;
КонецПроцедуры
Таким образом, происходит запуск и выполнение фонового задания из внешней обработки, подключенной к базе с помощью функционала дополнительных обработок БСП.
Процесс работы будет выглядеть следующим образом:
Данное выполнение реализовано только с помощью функционала БСП. Часто бывает, что данное отображение недостаточно наглядно отображает работу процесса, и пользователи требуют строку индикации, потому что, известно, смотреть бесконечно можно на три вещи: огонь, воду и заполняющуюся строку индикации в 1с.
Эту возможность можно реализовать несколькими способами, в данной же статье предлагается 2 варианта: с помощью редактирования общей формы конфигурации «ДлительнаяОперация» и с выводом индикации прямо на форму внешней обработки.
1. Вывод индикации в форме «ДлительнаяОперация».
Редактировать форму будем с помощью расширений. Важно отметить, что данная возможность использования расширений — замена произвольной процедуры в заимствованном модуле — стала реализована только в версии платформы 8.3.9, поэтому режим совместимости конфигурации и расширения должен быть 8.3.9 и выше или вообще отключен.
В форме добавляем в процедуру «ПриСозданииНаСервере» код по добавлению реквизита и элемента формы «Индикатор»:
&НаСервере
Процедура Расш1_ПриСозданииНаСервереПосле(Отказ, СтандартнаяОбработка)
ДобавляемыеРеквизиты = Новый Массив;
РеквизитИндикатор = Новый РеквизитФормы("Индикатор", ОбщегоНазначения.ОписаниеТипаЧисло(10,0));
ДобавляемыеРеквизиты.Добавить(РеквизитИндикатор);
ЭтаФорма.ИзменитьРеквизиты(ДобавляемыеРеквизиты);
ЭлементИндикатор = ЭтаФорма.Элементы.Добавить("Индикатор", Тип("ПолеФормы"), ЭтаФорма);
ЭлементИндикатор.Вид = ВидПоляФормы.ПолеИндикатора;
ЭлементИндикатор.ПутьКДанным= "Индикатор";
ЭлементИндикатор.ОтображатьПроценты = Истина;
КонецПроцедуры
Далее заменяем исполняемую в модуле общей формы процедуру, в которой происходит считывание прогресса выполнения и вывод информации на форму, и добавляем строку:
//... ЭтаФорма.Индикатор = Задание.Прогресс.Процент; //...
Таким образом, при запуске фонового задания будет открыта форма длительной операции с индикатором прогресса.

2. Вывод индикации в форме внешней обработки.
Для реализации данного способа добавим на форму 2 реквизита и соответствующих элемента: Индикатор (тип Число) и СтрокаСостояния (тип Строка).
Идея способа заключается в том, чтобы прочитать прогресс выполняемого задания в форме и вывести данные пользователю, не открывая форму длительной операции.
Для этого добавим Обработчик ожидания, который будет считывать прогресс и выводить его на форму, и саму процедуру считывания прогресса на сервере.
&НаКлиенте
#Область Индикатор
&НаКлиенте
Процедура ОбработчикОжиданияИндикатор() Экспорт
Прогресс = ПрочитатьПрогресс(ИДЗадания);
Если НЕ ТипЗнч(Прогресс) = Тип("Структура") Тогда
СтрокаСостояния = "";
Возврат;
КонецЕсли;
Если ТипЗнч(Прогресс) = Тип("Структура")
И Прогресс.Свойство("ЗавершеноАварийно") Тогда
ОтключитьОбработчикОжидания("ОбработчикОжиданияИндикатор");
Возврат;
КонецЕсли;
Если Прогресс.Свойство("ЗаданиеВыполнено") И Прогресс.ЗаданиеВыполнено Тогда
Индикатор = 100;
СтрокаСостояния = "Задание завершено.";
Иначе
Если Прогресс.Свойство("Процент") Тогда
Индикатор = Прогресс.Процент;
КонецЕсли;
Если Прогресс.Свойство("Текст") Тогда
СтрокаСостояния = Прогресс.Текст;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция ПрочитатьПрогресс(Знач ИдентификаторФоновогоЗадания) Экспорт
Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторФоновогоЗадания);
Если Задание = Неопределено Тогда
Возврат Неопределено;
КонецЕсли;
Если Задание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда
ОтключитьОбработчикОжидания("ОбработчикОжиданияИндикатор");
Возврат Неопределено;
КонецЕсли;
ПрогрессЗадания = ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторФоновогоЗадания);
// Добавляем флаг "ЗаданиеВыполнено", чтобы различать случаи: когда отсутствуют сообщения и когда завершено задание.
Если ПрогрессЗадания = Неопределено
Или ТипЗнч(ПрогрессЗадания) Тип("Структура") Тогда // или нет задания, или нет сообщений
ПрогрессЗадания = Новый Структура;
КонецЕсли;
ПрогрессЗадания.Вставить("ЗаданиеВыполнено", ДлительныеОперации.ЗаданиеВыполнено(ИдентификаторФоновогоЗадания));
Возврат ПрогрессЗадания;
КонецФункции
#КонецОбласти
В ранее добавленные процедуры добавим код для работы индикации:
— в процедуре ЗапуститьВыполнение обнулим наши реквизиты при запуске нового задания, отключим необходимость открытия окна ожидания и подключим наш обработчик ожидания:
&НаКлиенте
&НаКлиенте
Процедура ЗапуститьВыполнение(Команда)
ИДЗадания = "";
Индикатор = 0;
СтрокаСостояния = "";
ПараметрыЗапуска = ПодготовитьДанныеДляДлительнойОперации();
СтруктураФоновогоЗадания = ВыполнитьФоновоеЗаданиеНаСервере(ПараметрыЗапуска, УникальныйИдентификатор);
ИДЗадания = СтруктураФоновогоЗадания.ИдентификаторЗадания;
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
// указываем необходимость вывода окна с индикацией
//если используем индикатор на форме, то вывод окна можно установить как Ложь
ПараметрыОжидания.ВыводитьОкноОжидания = Ложь;
// указываем необходимость вывода прогресса состояния
ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина;
// указываем интервал обновления состояния в секундах, если не указать,
// то интервал будет увеличиваться при каждой итерации в 1.4 раза.
ПараметрыОжидания.Интервал = 2;
ДлительныеОперацииКлиент.ОжидатьЗавершение(
СтруктураФоновогоЗадания,
Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект),
ПараметрыОжидания);
//++Индикатор
ПодключитьОбработчикОжидания("ОбработчикОжиданияИндикатор",2);
//--Индикатор
КонецПроцедуры
-в процедуре ОбработатьДанные добавим обработку прогресса при завершении выполнения задания:
&НаКлиенте
&НаКлиенте
Процедура ОбработатьДанные(Результат, ДополнительныеПараметры) Экспорт
//++Индикатор
ОтключитьОбработчикОжидания("ОбработчикОжиданияИндикатор");
//--Индикатор
Если Результат = Неопределено Тогда
Возврат;
ИначеЕсли Результат.Статус = "Ошибка" Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(Результат.ПодробноеПредставлениеОшибки);
//++Индикатор
СтрокаСостояния = "Задание завершено с ошибками.";
//--Индикатор
ИначеЕсли Результат.Статус = "Выполнено" Тогда
// обрабатываем результат
Данные = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
ВозвратноеЗначение = Данные.Количество();
//++Индикатор
Индикатор = 100;
СтрокаСостояния = "Задание завершено.";
//--Индикатор
КонецЕсли;
КонецПроцедуры
Архив с обработкой и расширением:
ДлительныеОперацииВоВнешнейОбработке



Comments
So empty here ... leave a comment!