Фоновое задание в модуле внешней обработки

1. retr0 20.07.21 13:12 Сейчас в теме
Почитал разные варианты решения с использованием фонового задания в модуле объекта внешней обработки. Максимально похожий на правду этот и этот, но мне не нравится реализация некоторых моментов.

1) Там используется просто сохранении копии обработки на сервере и помещении во временное хранилище.
2) И в функции ДлительныеОперации.ВыполнитьПроцедуру()/ВыполнитьВФоне() - указывают в качестве исполняемого метода - метод "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки".

Вот 2 пункта которые мне не нравятся. Поскольку как мне кажется я нашел более лаконичный прием, хоть и делает тоже самое, почти.

1) Сначала выполняю НачатьПомещениеФайлаНаСервер()
2) Подключаю внешнею обработку, по адресу в хранилище. ВнешнииОбработки.Подключить(Адрес)
На этих пунктах все ок. После выполнения п.2 возвращается имя подключенной обработки = имя файла без расширения.

Проблема начинается когда я пытаюсь выполнить
ДлительныеОперации.ВыполнитьПроцедуру(, "ВнешняяОбработка."+ИмяОбработки+".МодульОбъекта.МойМетод")
Да, да именно так и должен собираться метод - слова "МодульОбъекта" обязательны.

Так вот, там по сути выполняется метод ВнешнииОбработки.Создать() - но на этом месте вылетает ошибка с тем, что якобы файл не обнаружен. Хотя я пробовал тоже самое выполнить в п.2 Сначала подключаю, потом создаю и тут это работает даже могу выполнить экспортную процедуру и модуля объекта и все ок. Эти шаги в синтаксис-помощнике описаны. Но в модуле ДлительныеОперациии не работает. Я проверял, что там в параметрах передается (все нормально). Просто как будто на этом этапе обработка уже не доступна или типа того. Неужели вот это все хрень и не нужно выполнять "ВнешнииОбработки.Подключенить(Адрес)", а достаточно просто записать копию на сервере?
По теме из базы знаний
Найденные решения
14. retr0 20.07.21 17:05 Сейчас в теме
Короче я разгадал тайну, оказывается нужно было все таки temp-файл записать.
Остальные ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
4. RocKeR_13 1325 20.07.21 14:02 Сейчас в теме
(1) Если обработка подключена как внешняя, то в качестве параметров задания использую следующую структуру:
	ПараметрыЗадания = Новый Структура;
	ПараметрыЗадания.Вставить("ИмяМетода", ИмяМетода);
	ПараметрыЗадания.Вставить("ПараметрыВыполнения", ПараметрыОбработки);
	ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", Истина);
	ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка", ВнешняяОбработка);

Ссылка на открываемую внешнюю обработку содержится в параметрах формы в свойстве "ДополнительнаяОбработкаСсылка"
Если обработка открывается через Файл-Открыть, то параметры задания передаю следующие
	ПараметрыЗадания = Новый Структура;

	ПараметрыЗадания.Вставить("ИмяОбработки", ПутьНаСервере);
	ПараметрыЗадания.Вставить("ИмяМетода", ИмяМетода);
	ПараметрыЗадания.Вставить("ПараметрыВыполнения", ПараметрыОбработки);
	ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", Истина);


ПутьНаСервере - это полный путь к файлу обработки на сервере (сохраняю его предварительно во временные файлы, при закрытии формы удаляю)
В обоих случаях в качестве выполняемого метода использую "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки"
ИмяМетода в параметрах задания - это как раз экспортная процедура модуля обработки

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

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

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

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

&НаСервереБезКонтекста
Функция ФайлСуществуетНаСервере(ПутьНаСервере)
	
	Файл = Новый Файл(ПутьНаСервере);
	Возврат Файл.Существует();
	
КонецФункции

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

&НаКлиенте
Функция ИспользуемоеИмяФайла()
	
	ПутьНаКлиенте = ПолучитьИмяФайлаНаКлиенте();
	ДвоичныеДанные = Новый ДвоичныеДанные(ПутьНаКлиенте);
	Возврат СохранитьОбработкуНаСервере(ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор));
 	   
КонецФункции

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

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

&НаКлиенте
Процедура ПрогрессВыполнения(Результат, Контекст) Экспорт
	
	Если Результат.Статус = "Выполняется" или Результат.Статус = "Выполнено" Тогда
		
		Прогресс = Результат.Прогресс;
		
		
		Если Прогресс <> Неопределено Тогда  
			
			Индикатор = Прогресс.Процент; // Индикатор - полей Индикатор на форме
			Элементы.ДекорацияПояснение.Заголовок = Прогресс.Текст; // поле надпись на форме
			
		КонецЕсли;
		
	КонецЕсли;
	
	Если Результат.Статус = "Выполнено" Или Результат.Статус = "Отменено" Тогда
		Элементы.ГруппаИндикация.Видимость = Ложь;
	КонецЕсли;
	 
КонецПроцедуры

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

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

	КонецЕсли;

КонецПроцедуры
Показать


Прогресс "сообщаю" в экспортной процедуре:
ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, "Выгружено строк: "+Строка(Итератор-2)+" из "+Строка(Всего));
6. retr0 20.07.21 14:16 Сейчас в теме
(4) Слишком много не нужных манипуляций, это те самые о которых я указал как "неприемлемые действия для меня". Я это доработал, и все работает в пару строк буквально. Без излишек в заполнении каких-то параметров, и записи обработки через temp-файл.
8. RocKeR_13 1325 20.07.21 15:29 Сейчас в теме
(6) Опять же, а чем не устроил штатный механизм БСП, когда обработка загружается в список внешних обработок (в этом случае никаких временных файлов не нужно создавать)? Там все излишества, по большому счету - это отображение прогресса выполнения.
9. retr0 20.07.21 15:51 Сейчас в теме
(8) Во-первых, я продублирую свой вопрос "ЧТО ЗА ШТАТНЫЙ МЕХАНИЗМ БСП"? Во-вторых, я так и сделал. Может еще раз внимательней ознакомишься с моим вопросом, такое ощущение будто сам себе отвечаешь. xD
10. RocKeR_13 1325 20.07.21 16:16 Сейчас в теме
(9) Вы сделали совсем иначе, нежели я описал) Если обработка загружена в справочник дополнительных обработок, не нужно отображать прогресс выполнения и не нужна обработка результата выполнения, то запуск в фоне будет следующим:

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

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


Собственно, здесь используется типовые механизмы БСП для параметризации фонового задания и, собственно,его запуска.
11. RocKeR_13 1325 20.07.21 16:23 Сейчас в теме
(9) с другой стороны, если не требуется интерактивное взаимодействие с обработкой, то процедуру внешней обработки можно запускать в фоне по расписанию. Как это сделать, можно почитать, например, тут
12. retr0 20.07.21 16:43 Сейчас в теме
(11) Во, сейчас ответ более осмысленный) В этом весь и прикол, я не хочу никуда эту обработку загружать, мне нужно открыл запустил 1 раз задание и все. Оно выполнилось. Конец. Эта обработка за раз кучу объектов читает, записывает. Поэтому надо ее в фоне. Врятли когда-либо она еще мне пригодится. Если бы, она была нужна, я бы вообще все в общем модуле через фоновое задание сделал и все. Может объяснишь тогда соль. При открытии обработки, у меня выполняется процедура
НачатьПомещениеФайлаНаСервер
и в обработке описания оповещения, мне возвращается некоторая информация по файлу и его адрес во временном хранилище, далее я передаю адрес для подключения этой внешней обработки по адресу
ВнешниеОбработки.Подключить(Адрес)
, мне возвращается имя файла, все ок. а потом запускаю выполнение основной процедуры через длительные операции. Но тут случается прикол, если я передаю в качестве выполняемого метода, такой путь: "ВнешняяОбработка."+ИмяОбработки+".МодульОбъекта.МояПроцедура" то он начинает выполнять в основном потоке и это работает. А если если передаю "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки" то, начинает выполнять уже в фоне, и выдает ошибку на том что файл не найден.
15. RocKeR_13 1325 20.07.21 17:06 Сейчас в теме
(12)
А если если передаю "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки" то, начинает выполнять уже в фоне, и выдает ошибку на том что файл не найден.

Так там уже процедура ждет полный путь к файлу на сервере, а не адрес во временном хранилище. поэтому и приходится его в temp сохранять, а потом удалять
17. retr0 20.07.21 17:15 Сейчас в теме
(15) Так я и не адрес во временном хранилище передаю. Адрес во временном хранилище используется только в контексте модуля формы и за его пределы не выходит. С помощью адреса во временном хранилище я использую объект "ВнешниеОбработки" и его метод "Подключить" в параметр передаю адрес временного хранилища, он же мне возвращает имя обработки. Во временном хранилище лежат двоичные данные обработки.
18. RocKeR_13 1325 20.07.21 17:16 Сейчас в теме
(17) ну так конечно, фоновое задание запускается в отдельном сеансе, который о подключенной обработке ничего не знает
13. retr0 20.07.21 16:51 Сейчас в теме
(11) В обоих случаях когда код выполняется в основном потоке и в фоне. Там выполняется:
ВнешниеОбработки.Создать(ИмяФайла)

Видимо он в основном потоке имеет доступ то ли к двоичным данным, то к файлу в целом.
Но в фоновом процессе он уже не может получить доступ, для него всего этого нет.
16. RocKeR_13 1325 20.07.21 17:15 Сейчас в теме
(13) Вообще в качестве ИмяФайла здесь должен быть полный путь к файлу обработки
2. retr0 20.07.21 13:25 Сейчас в теме
Ладно вопрос, снимаю, просто заработало, ничего не делал.
3. soft_wind 20.07.21 13:42 Сейчас в теме
а чем механизм БСП не подошел? там можно внешние обработки запускать как регламентные задания (они же фоновые)
5. retr0 20.07.21 14:11 Сейчас в теме
(3) Какой механизм конкретно?
7. soft_wind 20.07.21 14:41 Сейчас в теме
(6) Понятно, спасибо.
действительно, я тоже, где-то использовал подобную конструкцию
правда через попытку,

		Выполнить("Задание = ДлительныеОперации.ЗапуститьВыполнениеВФоне(
			|ЭтаФорма.УникальныйИдентификатор,
			|""ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки"",
			|ПараметрыМетода,
			|прДанные.ИмяМетода);");
		
14. retr0 20.07.21 17:05 Сейчас в теме
Короче я разгадал тайну, оказывается нужно было все таки temp-файл записать.
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот