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!