Пример использования асинхронной длительной операции в 1с с отображением прогресса на базе БСП

от автора

Введение

Привет всем! В данной статье предлагаю алгоритм по-шагового разбора примера создания «Длительной операции» на базе библиотеки стандартных подсистем (БСП). Всем кому интересно, что такое БСП — можете почитать в других моих статьях.

В публикации я постараюсь придерживаться стандартов разработки, основанных на системе БСП.

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

Не буду использовать расширения — не считаю нужным в этом примере. Так же посмотрим некоторые новые функции БСП для работы с «длительными операциями«.

 

Разработка задания с отражением состояния на форме «Длительной операции»

Свою разработку я начну с написания общего серверного модуля, в котором размещу процедуру для длительной операции. Добавляем вот такой текст процедуры:

&НаСервере Процедура ПровестиДокументы222(Параметры, АдресРезультата) Экспорт  //МассивВозврат = Новый Массив;  ПоискДляПроведения = Новый Запрос("ВЫБРАТЬ                                   |РеализацияТоваровУслуг.Ссылка КАК Ссылка                                   |ИЗ                                   |Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг                                   |ГДЕ                                   |РеализацияТоваровУслуг.Дата МЕЖДУ &Дата1 И &Дата2                                   |И РеализацияТоваровУслуг.Организация = &Организация                                   |                                   |УПОРЯДОЧИТЬ ПО                                   |РеализацияТоваровУслуг.Дата");  ПоискДляПроведения.УстановитьПараметр("Дата1", Параметры.ДатаНач1); ПоискДляПроведения.УстановитьПараметр("Дата2", Параметры.ДатаОкон1); ПоискДляПроведения.УстановитьПараметр("Организация", Параметры.Орг1);  НашлиДокументы = ПоискДляПроведения.Выполнить().Выгрузить();  ВсегоДокументов = НашлиДокументы.Количество();  ТекДок = 1;  Для Каждого Стр11 ИЗ НашлиДокументы Цикл  Док = Стр11.Ссылка.ПолучитьОбъект();  Док.Проведен = Ложь; Док.ПометкаУдаления = Ложь;  Попытка Док.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Неоперативный); Исключение Док.Записать(РежимЗаписиДокумента.Запись); КонецПопытки;  ПроцентВыполнения = (ТекДок/ВсегоДокументов)*100; ПроцентВыполнения = Окр(ПроцентВыполнения,0);  //МассивВозврат.Добавить(ПроцентВыполнения);  // сообщаем "процент" и "текст сообщения" ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения,СокрЛП(Док.Ссылка));  ТекДок = ТекДок + 1;  КонецЦикла;  //ПоместитьВоВременноеХранилище(МассивВозврат, АдресРезультата);  КонецПроцедуры

Данная процедура очень простенькая, но для того, чтобы она работала и «отдавала» состояние пользователю нам нужно — во-первых правильно передать ей структуру параметров, чтобы она «запустилась» вообще и во-вторых — использовать функционал БСП сообщать прогресс «Процентом», «Текстом» ДлительныеОперации.СообщитьПрогресс.

На этом разработка общего модуля так быстро завершена и я перейду к программированию внешней обработки, в которой напишем всю «обвязку» к длительной операции процедурыПровестиДокументы222.

Для начала нарисуем форму обработки:

Макет формы обработки "длительной операции"
Макет формы обработки «длительной операции»

Добавим в форму вот такие реквизиты:

Добавление реквизитов
Добавление реквизитов

Пройдемся по реквизитам : ДатаНачала, ДатаОкончания и Организация — это необходимые реквизиты для запуска процедуры «на удаленке — в фоне».

Индикатор и СтрокаСостояния — вспомогательные реквизиты отображения на форме обработки

ИдЗадания — один из важных реквизитов (он не выводится на форму) — это уникальный идентификатор создаваемого фонового задания, по которому это задание можно будет «отловить» в дальнейшем.

Начнем с написания кода кнопки «Запустить операцию» на форме обработки. Он выглядит вот так — можно его просто скопировать и привязать действие к кнопке (как и все далее — будет сразу работать, кстати):

&НаКлиенте Процедура ЗапуститьОперацию(Команда)  ИДЗадания = ""; Индикатор = 0; СтрокаСостояния = "";  ПараметрыЗапуска = Новый Структура; ПараметрыЗапуска.Вставить("ДатаНач1", НачалоДня(ЭтаФорма.ДатаНачала)); ПараметрыЗапуска.Вставить("ДатаОкон1",КонецДня(ЭтаФорма.ДатаОкончания)); ПараметрыЗапуска.Вставить("Орг1",  ЭтаФорма.Организация);  СтруктураФоновогоЗадания = ВыполнитьФоновоеЗаданиеНаСервере(ПараметрыЗапуска, УникальныйИдентификатор); ИДЗадания = СтруктураФоновогоЗадания.ИдентификаторЗадания;  ПараметрыОжидания  = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект); ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина; ПараметрыОжидания.Интервал  = 2;  ДлительныеОперацииКлиент.ОжидатьЗавершение(СтруктураФоновогоЗадания, Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект), ПараметрыОжидания);  КонецПроцедуры 

В этой процедуре мы заполняем ПараметрыЗапуска  для структуры фонового задания, задаем вывод ПрогрессаВыполнения с интервалом на форму длительной операции. Также, мы «активируем» фоновое задание и «отслеживаем его» с помощью ДлительныеОперацииКлиент.ОжидатьЗавершение().

 

Опишем оповещение «ОбработатьДанные«. Это оповещение вызывается при завершении фонового задания. Выглядит вот так:

&НаКлиенте Процедура ОбработатьДанные(Результат, ДополнительныеПараметры) Экспорт  ОтключитьОбработчикОжидания("ОбработчикОжиданияИндикатор");  Если Результат = Неопределено Тогда Возврат; ИначеЕсли Результат.Статус = "Ошибка" Тогда ОбщегоНазначенияКлиентСервер.СообщитьПользователю(Результат.ПодробноеПредставлениеОшибки); ЭтаФорма.СтрокаСостояния = "Ошибка"; ИначеЕсли Результат.Статус = "Выполнено" Тогда ЭтаФорма.Индикатор = 100; ЭтаФорма.СтрокаСостояния = "Выполнено"; КонецЕсли;  КонецПроцедуры 

 

Теперь, опишем основную функцию внешней обработки ВыполнитьФоновоеЗаданиеНаСервере(). Выглядит она вот так:

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

В принципе, все — можно уже работать и получать информацию о статусе фонового задания.

Отмечу сразу, что функция БСП «ВыполнитьВФоне» уже немного устарела. Взамен ее рекомендуют использовать функции — ВыполнитьФункцию и ВыполнитьПроцедуру. Но, о них я напишу чуть позже.

 

Процесс выполнения фонового задания в «стандартном режиме» будет выглядеть вот так:

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

 

Разработка задания с отражением состояния на форме внешней обработки

Для этого изначально доработаем нашу исходную процедуру — повесим в нее «обработчик ожидания» на отслеживание нашего состояния по заданному уникальному идентификатору

&НаКлиенте Процедура ЗапуститьОперацию(Команда)  ИДЗадания = ""; Индикатор = 0; СтрокаСостояния = "";  ПараметрыЗапуска = Новый Структура; ПараметрыЗапуска.Вставить("ДатаНач1", НачалоДня(ЭтаФорма.ДатаНачала)); ПараметрыЗапуска.Вставить("ДатаОкон1",КонецДня(ЭтаФорма.ДатаОкончания)); ПараметрыЗапуска.Вставить("Орг1",  ЭтаФорма.Организация);   СтруктураФоновогоЗадания  = ВыполнитьФоновоеЗаданиеНаСервере(ПараметрыЗапуска, УникальныйИдентификатор); ИДЗадания = СтруктураФоновогоЗадания.ИдентификаторЗадания;  ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект); //ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина; //ПараметрыОжидания.Интервал = 2;         ПараметрыОжидания.ВыводитьОкноОжидания = Ложь;  ДлительныеОперацииКлиент.ОжидатьЗавершение(СтруктураФоновогоЗадания, Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект), ПараметрыОжидания);  // подключим обработку ожидания получения "отклика" на форму ПодключитьОбработчикОжидания("ОбработчикОжиданияИндикатор",5);  КонецПроцедуры

 

Так же, заблокируем Интервал и ВыводитьПрогрессВыполнения. И добавим ПараметрыОжидания.ВыводитьОкноОжидания = Ложь (запрет вывода типовой формы длительной операции).

 

Опишем процедуру ПодключитьОбработкиОжиданияОбработчикОжиданияИндикатор. Выглядит она вот так:

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

 

Серверная функция ПрочитатьПрогресс на базе БСП библиотеки — выглядит вот так:

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

 

Итог работы данных изменений и добавлений в обработку будет такой:

Выполнение длительной операции
Выполнение длительной операции

Заключение и выводы

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

Всем спасибо за прочтение данной статьи. Вы так же можете ознакомиться с рядом других моих статей, посвященным стандартам и методам программирования в 1с с помощью библиотеки стандартных подсистем


ссылка на оригинал статьи https://habr.com/ru/post/708140/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *