Почитал разные варианты решения с использованием фонового задания в модуле объекта внешней обработки. Максимально похожий на правду этот и этот, но мне не нравится реализация некоторых моментов.
1) Там используется просто сохранении копии обработки на сервере и помещении во временное хранилище.
2) И в функции ДлительныеОперации.ВыполнитьПроцедуру()/ВыполнитьВФоне() - указывают в качестве исполняемого метода - метод "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки".
Вот 2 пункта которые мне не нравятся. Поскольку как мне кажется я нашел более лаконичный прием, хоть и делает тоже самое, почти.
1) Сначала выполняю НачатьПомещениеФайлаНаСервер() 2) Подключаю внешнею обработку, по адресу в хранилище. ВнешнииОбработки.Подключить(Адрес) На этих пунктах все ок. После выполнения п.2 возвращается имя подключенной обработки = имя файла без расширения.
Да, да именно так и должен собираться метод - слова "МодульОбъекта" обязательны.
Так вот, там по сути выполняется метод ВнешнииОбработки.Создать() - но на этом месте вылетает ошибка с тем, что якобы файл не обнаружен. Хотя я пробовал тоже самое выполнить в п.2 Сначала подключаю, потом создаю и тут это работает даже могу выполнить экспортную процедуру и модуля объекта и все ок. Эти шаги в синтаксис-помощнике описаны. Но в модуле ДлительныеОперациии не работает. Я проверял, что там в параметрах передается (все нормально). Просто как будто на этом этапе обработка уже не доступна или типа того. Неужели вот это все хрень и не нужно выполнять "ВнешнииОбработки.Подключенить(Адрес)", а достаточно просто записать копию на сервере?
Ссылка на открываемую внешнюю обработку содержится в параметрах формы в свойстве "ДополнительнаяОбработкаСсылка"
Если обработка открывается через Файл-Открыть, то параметры задания передаю следующие
ПутьНаСервере - это полный путь к файлу обработки на сервере (сохраняю его предварительно во временные файлы, при закрытии формы удаляю)
В обоих случаях в качестве выполняемого метода использую "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки"
ИмяМетода в параметрах задания - это как раз экспортная процедура модуля обработки
Примерно все выглядит следующим образом
ВнешняяОбработка - реквизит формы с типом СправочникСсылка.ДополнительныеОтчетыИОбработки, инициализируется при создании формы
ПутьНаСервере - реквизит формы с типом Строка (хранит путь к обработке на сервере)
&НаКлиенте
Процедура НачатьПодготовкуФайлаВФоне()
Состояние("Подготовка данных...");
Если Не ЗначениеЗаполнено(ВнешняяОбработка) И ПустаяСтрока(ПутьНаСервере) Тогда
ПутьНаСервере = ИспользуемоеИмяФайла();
ИначеЕсли Не ЗначениеЗаполнено(ВнешняяОбработка) И Не ПустаяСтрока(ПутьНаСервере) Тогда
Если Не ФайлСуществуетНаСервере(ПутьНаСервере) Тогда
ПутьНаСервере = ИспользуемоеИмяФайла();
КонецЕсли;
КонецЕсли;
ИмяЗадания = "Выгрузка данных в шаблон Excel";
ПараметрыЗапуска = ПодготовитьДанные(); // тут массив структур, передается в качестве параметра процедуры
ДлительнаяОперация = ЗапуститьДлительнуюОперацию("ПодготовитьДанныеПоТоварамНаСервере", ПараметрыЗапуска, ИмяЗадания);
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина;
ПараметрыОжидания.ВыводитьОкноОжидания = Ложь;
ПараметрыОжидания.ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект); // для отображения прогресса
ПараметрыОжидания.Интервал = 2;
Доступность = Ложь;
Состояние("Ожидайте завершения процесса подготовки файла Excel...");
ДлительныеОперацииКлиент.ОжидатьЗавершение(
ДлительнаяОперация,
Новый ОписаниеОповещения("ВыполнитьПроцедуруФоново_Выполнено", ЭтотОбъект),
ПараметрыОжидания);
КонецПроцедуры
&НаСервереБезКонтекста
Функция ФайлСуществуетНаСервере(ПутьНаСервере)
Файл = Новый Файл(ПутьНаСервере);
Возврат Файл.Существует();
КонецФункции
&НаСервере
Функция ЗапуститьДлительнуюОперацию(ИмяМетода, ПараметрыОбработки, ИмяЗадания)
ВыполняемыйМетод = "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки";
ПараметрыЗадания = Новый Структура;
Если Не ЗначениеЗаполнено(ВнешняяОбработка) Тогда
ПараметрыЗадания.Вставить("ИмяОбработки", ПутьНаСервере);
КонецЕсли;
ПараметрыЗадания.Вставить("ИмяМетода", ИмяМетода);
ПараметрыЗадания.Вставить("ПараметрыВыполнения", ПараметрыОбработки);
ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", Истина);
Если ЗначениеЗаполнено(ВнешняяОбработка) Тогда
ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка", ВнешняяОбработка);
КонецЕсли;
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = ИмяЗадания;
РезультатФоновогоЗадания = ДлительныеОперации.ВыполнитьВФоне(ВыполняемыйМетод, ПараметрыЗадания, ПараметрыВыполнения);
Возврат РезультатФоновогоЗадания;
КонецФункции
&НаКлиенте
Функция ИспользуемоеИмяФайла()
ПутьНаКлиенте = ПолучитьИмяФайлаНаКлиенте();
ДвоичныеДанные = Новый ДвоичныеДанные(ПутьНаКлиенте);
Возврат СохранитьОбработкуНаСервере(ПоместитьВоВременноеХранилище(ДвоичныеДанные, УникальныйИдентификатор));
КонецФункции
&НаСервере
Функция ПолучитьИмяФайлаНаКлиенте()
ЭтотОб = РеквизитФормыВЗначение("Объект");
Возврат ЭтотОб.ИспользуемоеИмяФайла;
КонецФункции
&НаСервере
Функция СохранитьОбработкуНаСервере(АдресВХ)
ДвоичныеДанные = ПолучитьИзВременногоХранилища(АдресВХ);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("epf");
ДвоичныеДанные.Записать(ИмяВременногоФайла);
Возврат ИмяВременногоФайла;
КонецФункции
&НаКлиенте
Процедура ПрогрессВыполнения(Результат, Контекст) Экспорт
Если Результат.Статус = "Выполняется" или Результат.Статус = "Выполнено" Тогда
Прогресс = Результат.Прогресс;
Если Прогресс <> Неопределено Тогда
Индикатор = Прогресс.Процент; // Индикатор - полей Индикатор на форме
Элементы.ДекорацияПояснение.Заголовок = Прогресс.Текст; // поле надпись на форме
КонецЕсли;
КонецЕсли;
Если Результат.Статус = "Выполнено" Или Результат.Статус = "Отменено" Тогда
Элементы.ГруппаИндикация.Видимость = Ложь;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьПроцедуруФоново_Выполнено(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат;
ИначеЕсли Результат.Статус = "Ошибка" Тогда
Доступность = Истина;
ОбщегоНазначенияКлиент.СообщитьПользователю(Результат.ПодробноеПредставлениеОшибки);
ИначеЕсли Результат.Статус = "Выполнено" Тогда
Доступность = Истина;
Данные = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
Если Данные = Неопределено Тогда
Возврат;
КонецЕсли;
РежимВыбора = РежимДиалогаВыбораФайла.Сохранение;
Диалог = Новый ДиалогВыбораФайла(РежимВыбора);
Оповещение = Новый ОписаниеОповещения("СохранениеФайлаТовары_Завершение", ЭтотОбъект, Данные);
Диалог.Фильтр = "Файл EXCEL|*.xlsx";
Диалог.Заголовок = "Выберите файл для сохранения данных";
Диалог.Показать(Оповещение);
КонецЕсли;
КонецПроцедуры
Показать
Прогресс "сообщаю" в экспортной процедуре:
ДлительныеОперации.СообщитьПрогресс(ПроцентВыполнения, "Выгружено строк: "+Строка(Итератор-2)+" из "+Строка(Всего));
(4) Слишком много не нужных манипуляций, это те самые о которых я указал как "неприемлемые действия для меня". Я это доработал, и все работает в пару строк буквально. Без излишек в заполнении каких-то параметров, и записи обработки через temp-файл.
(6) Опять же, а чем не устроил штатный механизм БСП, когда обработка загружается в список внешних обработок (в этом случае никаких временных файлов не нужно создавать)? Там все излишества, по большому счету - это отображение прогресса выполнения.
(8) Во-первых, я продублирую свой вопрос "ЧТО ЗА ШТАТНЫЙ МЕХАНИЗМ БСП"? Во-вторых, я так и сделал. Может еще раз внимательней ознакомишься с моим вопросом, такое ощущение будто сам себе отвечаешь. xD
(9) Вы сделали совсем иначе, нежели я описал) Если обработка загружена в справочник дополнительных обработок, не нужно отображать прогресс выполнения и не нужна обработка результата выполнения, то запуск в фоне будет следующим:
&НаКлиенте
Процедура НачатьПодготовкуФайлаВФоне()
ИмяЗадания = "Выгрузка данных в шаблон Excel"; // имя фонового задания
ПараметрыЗапуска = ПодготовитьДанные(); // сюда передаем параметры для процедуры, выполняемой в фоне
ИмяПроцедуры = "ПодготовитьДанныеПоТоварамНаСервере"; // имя экспортной процедуры модуля обработки
ДлительнаяОперация = ЗапуститьДлительнуюОперацию(ИмяПроцедуры , ПараметрыЗапуска, ИмяЗадания);
КонецПроцедуры
&НаСервере
Функция ЗапуститьДлительнуюОперацию(ИмяМетода, ПараметрыОбработки, ИмяЗадания)
ВыполняемыйМетод = "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки";
ПараметрыЗадания = Новый Структура;
ПараметрыЗадания.Вставить("ИмяМетода", ИмяМетода);
ПараметрыЗадания.Вставить("ПараметрыВыполнения", ПараметрыОбработки);
ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", Истина);
ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка", ВнешняяОбработка); // ВнешняяОбработка - ссылка на элемент справочника дополнительных обработок
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = ИмяЗадания;
РезультатФоновогоЗадания = ДлительныеОперации.ВыполнитьВФоне(ВыполняемыйМетод, ПараметрыЗадания, ПараметрыВыполнения);
Возврат РезультатФоновогоЗадания;
КонецФункции
Показать
Собственно, здесь используется типовые механизмы БСП для параметризации фонового задания и, собственно,его запуска.
(9) с другой стороны, если не требуется интерактивное взаимодействие с обработкой, то процедуру внешней обработки можно запускать в фоне по расписанию. Как это сделать, можно почитать, например, тут
(11) Во, сейчас ответ более осмысленный) В этом весь и прикол, я не хочу никуда эту обработку загружать, мне нужно открыл запустил 1 раз задание и все. Оно выполнилось. Конец. Эта обработка за раз кучу объектов читает, записывает. Поэтому надо ее в фоне. Врятли когда-либо она еще мне пригодится. Если бы, она была нужна, я бы вообще все в общем модуле через фоновое задание сделал и все. Может объяснишь тогда соль. При открытии обработки, у меня выполняется процедура
НачатьПомещениеФайлаНаСервер
и в обработке описания оповещения, мне возвращается некоторая информация по файлу и его адрес во временном хранилище, далее я передаю адрес для подключения этой внешней обработки по адресу
ВнешниеОбработки.Подключить(Адрес)
, мне возвращается имя файла, все ок. а потом запускаю выполнение основной процедуры через длительные операции. Но тут случается прикол, если я передаю в качестве выполняемого метода, такой путь: "ВнешняяОбработка."+ИмяОбработки+".МодульОбъекта.МояПроцедура" то он начинает выполнять в основном потоке и это работает. А если если передаю "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки" то, начинает выполнять уже в фоне, и выдает ошибку на том что файл не найден.
А если если передаю "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки" то, начинает выполнять уже в фоне, и выдает ошибку на том что файл не найден.
Так там уже процедура ждет полный путь к файлу на сервере, а не адрес во временном хранилище. поэтому и приходится его в temp сохранять, а потом удалять
(15) Так я и не адрес во временном хранилище передаю. Адрес во временном хранилище используется только в контексте модуля формы и за его пределы не выходит. С помощью адреса во временном хранилище я использую объект "ВнешниеОбработки" и его метод "Подключить" в параметр передаю адрес временного хранилища, он же мне возвращает имя обработки. Во временном хранилище лежат двоичные данные обработки.
(11) В обоих случаях когда код выполняется в основном потоке и в фоне. Там выполняется:
ВнешниеОбработки.Создать(ИмяФайла)
Видимо он в основном потоке имеет доступ то ли к двоичным данным, то к файлу в целом.
Но в фоновом процессе он уже не может получить доступ, для него всего этого нет.