Запуск фонового задания с прогрессом во внешней обработке независимо от места вызова на Библиотеке стандартных подсистем

10.02.23

Разработка - БСП (Библиотека стандартных подсистем)

Открытый код. Реализован запуск как из справочника дополнительных обработок, так и с файла на диске без обязательного доступа с сервера. Используется актуальная процедура БСП ДлительныеОперации.ВыполнитьПроцедуру.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование SM По подписке [?] Купить один файл
Запуск фонового задания с прогрессом во внешней обработке независимо от места вызова на Библиотеке стандартных подсистем:
.epf 9,17Kb
15
15
1 SM
Скачать Купить за 1 850 руб.

МЕТОДЫ

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

 

СРЕДА

Тестировалось на конфигурации Управление Торговлей 11.4.13.227, версия БСП 3.1.3.548, платформа 8.3.17.1549

 

ДЕМОНСТРАЦИЯ

Нажать на кнопку "Обзор"  и выбрать любой файл Excel с клиента, версия формата 2007.

 

КОД

Модуль объекта

Функция СведенияОВнешнейОбработке() Экспорт
	
	ИмяОбработки = Метаданные().Имя;
	Синоним = Метаданные().Синоним;
	Синоним = ?(ПустаяСтрока(Синоним), ИмяОбработки, Синоним);
	
	ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке();
	ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
	ПараметрыРегистрации.Наименование = Синоним;
	ПараметрыРегистрации.Версия = "1.0";
	ПараметрыРегистрации.Информация = Синоним;
	ПараметрыРегистрации.БезопасныйРежим = Ложь;
	
	ТаблицаКоманд = ПараметрыРегистрации.Команды;
		
	Команда = ТаблицаКоманд.Добавить();
	Команда.Идентификатор = "ОткрытьОбработку";
	Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы();
	Команда.Представление = Синоним + " (открыть форму)";
	
	Возврат ПараметрыРегистрации;
	
КонецФункции

Процедура ЗагрузитьДанные(ПараметрыДлительнойОперации, АдресРезультата) Экспорт
	
	КоличествоСтрокВычисленияПрогресса = 1;
	ИмяВременногоФайла = ПолучитьИмяВременногоФайла("xlsx");
	
	ДлительныеОперации.СообщитьПрогресс(0, "Загрузка файла в систему...");
	
	ПараметрыДлительнойОперации.ДвоичныеДанные.Записать(ИмяВременногоФайла);
	ТабличныйДокумент.Прочитать(ИмяВременногоФайла, СпособЧтенияЗначенийТабличногоДокумента.Значение);
	ВысотаТаблицыБезЗаголовка = ТабличныйДокумент.ВысотаТаблицы - 1;
	
	ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабличныйДокумент.Область(1, 1, ТабличныйДокумент.ВысотаТаблицы, ТабличныйДокумент.ШиринаТаблицы));
	ПостроительОтчетов = Новый ПостроительОтчета;
	ПостроительОтчетов.ИсточникДанных = ИсточникДанных;
	ПостроительОтчетов.Выполнить();
	
	ВыборкаДетальныеЗаписи = ПостроительОтчетов.Результат.Выбрать();
	ТекущаяСтрока = 0;
	СчетчикПрогресса = 0;
	
	Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
	
		КакаяТоПроцедураОбработкиСтроки(ВыборкаДетальныеЗаписи);
		ТекущаяСтрока = ТекущаяСтрока + 1;
		СчетчикПрогресса = СчетчикПрогресса + 1;
		
		Если СчетчикПрогресса = КоличествоСтрокВычисленияПрогресса Тогда
			
			Процент = Формат(ТекущаяСтрока / ВысотаТаблицыБезЗаголовка * 100, "ЧДЦ=2");
			ДлительныеОперации.СообщитьПрогресс(Процент, СтрШаблон("Обработка %1 строки из %2", ТекущаяСтрока, ВысотаТаблицыБезЗаголовка));
			СчетчикПрогресса = 0;
			
		КонецЕсли;
		
	КонецЦикла;
	
	ДанныеРезультата = Новый Структура("ВсегоСтрок", ТекущаяСтрока);
	ПоместитьВоВременноеХранилище(ДанныеРезультата, АдресРезультата);
	
КонецПроцедуры

Процедура КакаяТоПроцедураОбработкиСтроки(ВыборкаДетальныеЗаписи)
	
	Ждать(1);
	
КонецПроцедуры

Процедура Ждать(КоличествоСекунд)
	
	Попытка
		
		Соединение = Новый HTTPСоединение("127.0.0.0",,,,,КоличествоСекунд);
		Соединение.Получить(Новый HTTPЗапрос());
		
	Исключение
	Конецпопытки;
	
КонецПроцедуры

 

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

На рабочей задаче обязательно задайте максимальный интервал, который будет удовлетворять пользователя в целях оптимизации, например 100.

Используется чтение табличным документом из файла, т.к. на данный момент Excel читается только так. Если же вы работаете с форматами MXL, ODS, то используйте чтение из потока в целях оптимизации. В процедуре КакаяТоПроцедураОбработкиСтроки в целях демонстрации выполняется ожидание длиной в 1 секунду.

 

 

Модуль формы

#Область ОбработчикиСобытийФормы

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

&НаКлиенте
Процедура ПриОткрытии(Отказ)
	
	Если ЗначениеЗаполнено(ПутьКВнешнейОбработке) Тогда
		
		АдресВнешнейОбработки = ПоместитьВоВременноеХранилище(Новый ДвоичныеДанные(ПутьКВнешнейОбработке), УникальныйИдентификатор);
		ЗаписатьКопиюОбработки(АдресВнешнейОбработки, ПутьКопииОбработки);
		
	КонецЕсли;
	
КонецПроцедуры

&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
	УдалитьКопиюОбработкиНаСервере(ПутьКопииОбработки);
КонецПроцедуры

#КонецОбласти

#Область ОбработчикиКомандФормы

&НаКлиенте
Процедура Обзор(Команда)
	
	ОписаниеОповещения = Новый ОписаниеОповещения("ОбзорПослеПомещенияФайла", ЭтотОбъект);
	ПараметрыЗагрузки = ФайловаяСистемаКлиент.ПараметрыЗагрузкиФайла();
	ПараметрыЗагрузки.ИдентификаторФормы = УникальныйИдентификатор;
	ПараметрыЗагрузки.Диалог.Фильтр = "Табличный документ (*.xlsx *.xls)|*.xlsx;*.xls";
	ФайловаяСистемаКлиент.ЗагрузитьФайл(ОписаниеОповещения, ПараметрыЗагрузки);
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

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

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

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

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

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

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

&НаСервереБезКонтекста
Процедура УдалитьКопиюОбработкиНаСервере(ПутьКопииОбработки)

	Если Не ЗначениеЗаполнено(ПутьКопииОбработки) Тогда
		Возврат;
	КонецЕсли;
		
	ФайлОбработки = Новый Файл(ПутьКопииОбработки);
	
	Если ФайлОбработки.Существует() Тогда
		УдалитьФайлы(ПутьКопииОбработки);
	КонецЕсли;

КонецПроцедуры // УдалитьКопиюОбработкиНаСервере(ПутьКопииОбработки)()

#КонецОбласти

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

В функции ЗагрузитьСтатусыНаСервере структура ПараметрыДлительнойОперации определяет параметры для основной процедуры из модуля объекта, в примере в параметрах передается полученный с клиента файл Excel в виде двоичных данных. Ключ ДополнительныйРезультат вместо АдресРезультата используется из-за безусловного алгоритма разработчиков БСП в вызове ДлительныеОперации.ВыполнитьПроцедуру.

Реквизит Отладка необходим для запуска алгоритма не в фоне для быстрой отладки на клиент-серверных базах без необходимости добавлять параметр запуска РежимОтладки в конфигураторе. На рабочей задаче необходимо скрыть данный реквизит на форме.

Именно процедура ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки позволяет запускать процедуры из модуля обработки. В зависимости от места запуска мы передаем либо ссылку, либо путь к временному файлу, куда скопирована обработка ранее. После завершения обработки в процедуре ОбзорПослеПомещенияФайлаЗавершение мы обращаемся именно к ключу АдресДополнительногоРезультата.

 

Форма и реквизиты

 

 

Известные проблемы

В процессе разработки можно получить следующую ошибку:


 

Она появляется из-за запуска платформой внешней обработки не из файла на диске, а из кеша дополнительных обработок. Кейс ошибки: обновляется справочник дополнительных обработок из файла на диске, запускается форма из формы справочника, а затем в этом же сеансе открывается обработка из файла на диске напрямую. Подобная ситуация работает и в обратном случае.

Если же не запускать из обоих мест в одном сеансе, то ошибки не будет.

См. также

Инструментарий разработчика БСП (Библиотека стандартных подсистем) Программист Платформа 1С v8.3 Конфигурации 1cv8 Абонемент ($m)

Пример шаблона для многопоточного выполнения фонового задания на основе БСП. Шаблоны сделаны для процедуры и функции.

2 стартмани

03.05.2024    1264    18    Hitcher    3    

13

БСП (Библиотека стандартных подсистем) Адаптация типовых решений Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 Бесплатно (free)

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

01.03.2024    3598    dimanich70    8    

16

Механизмы платформы 1С БСП (Библиотека стандартных подсистем) Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Небольшая шпаргалка по функциям БСП касательно адреса. Так скажем, еще один способ помимо https://infostart.ru/1c/articles/1060970/

12.02.2024    1141    FilippovRI    0    

17

БСП (Библиотека стандартных подсистем) Механизмы типовых конфигураций Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Уже не одна веб-страница исписана знаниями о дополнительных обработках, как создать, как подключить. Есть масса вариантов, как их можно отладить. Я разобрался в кишках работы библиотеки и покажу, как можно расширить возможности дополнительных отчетов, а также покажу удобный способ отладки.

07.02.2024    3463    YA_418728146    11    

53
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. sandr13 35 09.09.23 14:19 Сейчас в теме
При испытании вылезает ошибка:
Ошибка при вызове метода контекста (Создать)
{ОбщийМодуль.ДлительныеОперации.Модуль(903)}:Обработка = ВнешниеОбработки.Создать(Параметры.ИмяОбработки, БезопасныйРежим);
{(1)}:ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки(Параметры[0],Параметры[1])
{ОбщийМодуль.ОбщегоНазначения.Модуль(5113)}:Выполнить ИмяМетода + "(" + ПараметрыСтрока + ")";
{ОбщийМодуль.ДлительныеОперации.Модуль(1041)}:ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыВызова);
{ОбщийМодуль.ДлительныеОперации.Модуль(1031)}:ВызватьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);

по причине:
Ошибка подключения внешних метаданных
по причине:
Каталог не обнаружен ''
при запуске указал очистку кэша не помогло. Версия УТ Управление торговлей, редакция 11 (11.4.13.275). Не думаю, что так сильно изменилась версия. В отладке при попытке выполнить строку ВнешниеОбработки.Создать(Параметры.ИмяОбработки, БезопасныйРежим), где Параметры.ИмяОбработки="", похоже что туда надо что-то вставить...
Оставьте свое сообщение