Каталог решений - Гарантированно рабочий пример использования длительных операций на БСП с отображением прогресса. [Часть 1]

Гарантированно рабочий пример использования длительных операций на БСП с отображением прогресса. [Часть 1]

Гарантированно рабочий пример использования длительных операций на БСП с отображением прогресса. [Часть 1]

В наличии

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

Категория:

Описание

 

Введение

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

Вы спросите — для чего эта статья? уже неоднократно разбиралась эта тема, зачем повторять? К своему удивлению, здесь на ресурсе я не нашел НИ ОДНОЙ реально "работающей" статьи по длительным операциям. В примерах много лишнего, много воды, недосказанности, другие примеры — откровенно устарели.

Моя публикация "подводит черту актуальности" на текущую дату — 28.10.2020 — я привожу рабочий пример с "длительной операцией", с отображением прогресса как на основной форме, так и на форме "длительной операции".

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

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

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

 

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

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

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

 

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

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

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

Рис.1 Базовая форма внешней обработки для запуска длительной операции

 

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

Рис.2 Необходимые реквизиты и их типы

 

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

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

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

 

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

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

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

 

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

&НаКлиенте
Процедура ОбработатьДанные(Результат, ДополнительныеПараметры) Экспорт

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

 

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

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

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

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

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

 

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

Рис.3 Отражение статуса выполнения запущенного фонового задания — в данном случае — это проведение документов.

 

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

 

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

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

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

 

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

 

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

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

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

 

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

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

 

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

Рис.4 Отражение статуса выполнения запущенного фонового задания на форме обработке. Окно выполнения фонового задания отключено. Но, процесс идет и отражается на идентификаторе и передает текущее состояние.

 

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

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

Хорошо это или плохо — 100 % оценить не могу, но по своему опыту всегда пользователь запускал обработку, которая "лочила" его действия в базе…. так, для надежности чтоли….

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

В своем примере я использовал Платформу 1с 8.3.17.1549 и конфигурацию БСП 3.1.3.303.

Еще раз отмечу — почему я решил написать данную статью — на ресурсе я не нашел ничего действенного, очень много лишнего пишет народ, много воды, не хватает вводных данных.

 

Функции данной статьи вы сможете скопировать к себе в обработку и это все будет работать. Спасибо, что прочитали данную статью.

 

Другие материалы

Так же прошу ознакомиться с другими моими статьями по БСП и типовым конфигурациям:

Работаем с контактной информацией в конфигурациях на БСП

Базовые вещи БСП, которые облегчат жизнь программисту 1С

Типовые методы конфигурации "Зарплата и управление персоналом", которые пригодятся каждому ЗУП программисту и не только

Полезные встроенные функции для работы с печатными формами и не только на УТ 11.4 и БП 3.0 (сравнение)

Возможности работы со строками при помощи БСП, которые должен знать каждый программист

has been added to your cart:
Оформление заказа