Произвольный код в фоновом режиме

Публикация № 842660

Программирование - Практика программирования

147
Задача: реализовать выполнение произвольного кода в фоновом режиме без изменения конфигурации, т.е. во внешней обработке.

Механизм фоновых заданий все чаще используется для распаралеливания задач. Подвисающее на несколько минут окно - уже не комильфо, а для каждой длительной операции пользователь хочет видеть прогресс бар. И все бы ничего пока код пишет программист, вставляет в конфигурацию и потом запускает, но как быть если код пишется в процессе и заранее не известен? Менеджер фоновых заданий для процедуры "Запустить" требует имя процедуры, код есть только в виде строки. Ограничения платформы? Не в этот раз!

Итак, прежде чем прикручивать педали, посмотрим что уже есть в БСП: ВыполнитьПроцедуруМодуляОбъектаОбработки(Параметры, АдресХранилища). Заполняем параметры:

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

Процедура получит внешнюю обработку из справочника или из файла(наш случай) и запустит указанный метод. Соль в том, что файл наш лежит на клиентском компьютере, местоположение на сервере скорее всего не доступно. Передаем файл на сервер и записываем его там: 

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


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

Итак, файл записали на сервере, запускаем фоновое задание, которому говорим запустить функцию из БСП, которая запустит наш метод из этого файла внешней обработки:

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

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

Ну и наконец подключим обработчик ожидания, который будет мониторить работу нашего фонового процесса и выводить прогресс и сообщения:

ПодключитьОбработчикОжидания("ПроверкаФоновогоЗадания",1,Ложь);

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

Функция ПроверкаФоновогоЗаданияНаСервере()
	Результат = Новый Структура("Прогресс,Состояние");
		
	Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
	ЗаполнитьЗначенияСвойств(Результат,Задание);
	Результат.Состояние= СТрока(Результат.Состояние);
	Если Задание = Неопределено Тогда
		Возврат Неопределено;
	Иначе
		
		Сообщения=Задание.ПолучитьСообщенияПользователю(Ложь);
		Для Каждого Сообщение ИЗ Сообщения Цикл
			Если Лев(Сообщение.Текст,1) <> "{" Тогда
				Сообщить(Сообщение.Текст);
			КонецЕсли;
		КонецЦикла;
		Прогресс = ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
		Если Прогресс <> Неопределено Тогда
			ПрогрессОбработки = Прогресс.Процент;//?(Прогресс.Процент<>0,Прогресс.Процент,ПрогрессОбработки);
		КонецЕсли;
		Результат.Вставить("Прогресс",Прогресс);
	КонецЕсли;

	Возврат Результат;
КонецФункции

&НаКлиенте
Процедура УбитьПроцесс(Команда)
	
	УбитьПроцессНаСервере();
	ОтключитьОбработчикОжидания("ПроверкаФоновогоЗадания");
	Сообщить(""+ТекущаяДата()+" задание выполнено");
	
КонецПроцедуры

&НаСервере
Процедура УбитьПроцессНаСервере()
	Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
	Задание.Отменить();
	Элементы.ГруппаФоновоеЗадание.Видимость=Ложь;
КонецПроцедуры

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

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

147

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. Infactum 273 03.09.18 17:26 Сейчас в теме
Чем типовые механизмы БСП не угодили? Там еще и контроль доступа для фонового задания задействовать можно будет.
DrAku1a; kiruha; +2 Ответить
2. nikita0832 170 03.09.18 22:36 Сейчас в теме
(1) читал я про эти методы, к сожалению нет идентификатора задания, а хотелось бы получать прогресс и выводить сообщения из фонового задания. а то от обычного кружка или котика радости мало))
BigB; DrAku1a; Vlad33k; +3 Ответить
3. RocKeR_13 550 04.09.18 15:37 Сейчас в теме
4. nikita0832 170 04.09.18 16:31 Сейчас в теме
(3) о да, она даже у меня в закладках есть) там есть привязка к "ИмяМодуля.ИмяЭкспортнойПроцедуры", ещё и замена общей формы, а задача - реализовать без изменения конфигурации.
5. Malfarion 190 04.09.18 18:52 Сейчас в теме
(4) Привет, не пробовал такой хак пройдет аудит на Fresh ? С учетом того что обработка во внешних, из файла понятно что не возьмет.
6. nikita0832 170 04.09.18 21:46 Сейчас в теме
(5) Нет, не пробовал, попробуй - нам расскажешь.
7. Malfarion 190 05.09.18 01:05 Сейчас в теме
19. vadim1011985 60 03.11.18 01:04 Сейчас в теме
(2) Вот сегодня реализовал подобную хотелку
&НаКлиенте
//Процедура запускает загрузку и анализ файлов выгрузки 
// 
Процедура ЗагрузитьИЗаписать(Команда)
	
	Состояние("Начало загрузки",1,"Начало загрузки данных");
		
	ПараметрыКоманды = 
  ДополнительныеОтчетыИОбработкиКлиент.ПараметрыВыполненияКомандыВФоне(Параметры.ДополнительнаяОбработкаСсылка);
	
	ПараметрыКоманды.СопровождающийТекст = НСтр("ru = 'Подождите идет загрузка данных'");
	
	ПараметрыКоманды.ФормаВладелец = ЭтаФорма;
	
	ПараметрыКоманды.Вставить("Каталог", Объект.Каталог);
	//ПараметрыКоманды.Вставить("Объект",Объект);
	ПараметрыКоманды.Вставить("ТипЗагрузкиДокументов",Объект.ТипЗагрузкиДокументов);
	ПараметрыКоманды.Вставить("НачПериода",Объект.НачПериода);
	ПараметрыКоманды.вставить("КонПериода",Объект.КонПериода);
	
	Обработчик = Новый ОписаниеОповещения("ПослеЗавершенияДлительнойОперации", ЭтотОбъект, ПараметрыКоманды.СопровождающийТекст); 
	
	ОбработчикПрогресса =  Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект);
				
	ВыполнитьКомандуВФоне(Параметры.ИдентификаторКоманды, ПараметрыКоманды, Обработчик,ОбработчикПрогресса);

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

/// Процедура повторяет код общего модуля ДлительныеОперации.ВыпонитьвФоне . добавлен параметр оповещение о прогрессе выполнения. плюс изменены параметры структуры настройки ожидания

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


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

		
	Если Результат.Статус = "Выполняется" Тогда
		Прогресс = Результат.Прогресс;
		Если Прогресс <> Неопределено Тогда
			
			Состояние (Прогресс.Текст, Прогресс.Процент,,);	
	     КонецЕсли;
	
	КонецЕсли;

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


Ну и соотвественно для сообщения прогресса использую ДлительныеОперации.СообщитьПроцесс
8. asved.ru 36 05.09.18 09:25 Сейчас в теме
Необходимо понимать, что объект внешней обработки, вызов метода которого выполняется в фоне - не тот же самый объект, форма которого открыта на клиенте.
9. nikita0832 170 05.09.18 12:01 Сейчас в теме
(8) Да, контекст в этом случае конечно отвалится. Я вообще вызываю процедуру из модуля объекта этой внешней обработки и туда передаю все что нужно. Рабочий пример если интересно здесь - https://infostart.ru/public/585055/ это по сути мой рабочий инструмент.
10. paybaseme 21 04.10.18 09:53 Сейчас в теме
11. Xershi 512 07.10.18 15:08 Сейчас в теме
Разрозненные куски кода, почти не понятно что и откуда.
Я так понимаю тут речь идет о том как внешнюю не подключенную обработку, запущенную через файл выполнить в фоне.
В целом получилось.
Добавил на форму реквизит "ПрогрессОбработки", число. После того как убрал комент в
Состояние("Выполняется алгоритм...",ПрогрессОбработки);

Также добавил на форму реквизит "ИдентификаторЗадания", УникальныйИдентификатор.
Как сделать прогресс бар без состояния не понятно.
Если база файловая и запущена через конфигуратор в отладке, фоновое задание не стартует, но это уже вопрос к БСП.
Если подключить обработку во внешние вываливается ошибка при сохранении, я так понимаю для подключения не задумывалось.

Сделал вот такую команду:
&НаСервере
Процедура Команда1НаСервере(ФайлОбработкиВоВременномХранилище)
	
	ИмяФайла = "Загрузка курсов валют НБРБ 2.0.epf";
	
	ДвоичныеДанныеНаСервере = ПолучитьИзВременногоХранилища(ФайлОбработкиВоВременномХранилище);
	АдресФайлаНаСервере = КаталогВременныхФайлов() + ИмяФайла;
	ДвоичныеДанныеНаСервере.Записать(АдресФайлаНаСервере);
	
	//СтруктураПараметров = Новый Структура("РезультатЗапроса,Код,Параметры", Результат[Результат.ВГраница()],Код,ПараметрыЗапроса);    
	
	ОбъектВЗначении = РеквизитФормыВЗначение("Объект");
	ТекущийСписокВалют = ОбъектВЗначении.СписокВалют.Выгрузить();
	
	СтруктураПараметров = Новый Структура();
	СтруктураПараметров.Вставить("ДополнительнаяОбработкаСсылка",	Объект.ОбъектСсылка);
	//ПараметрыКоманды.Вставить("АдресРезультата",				ПоместитьВоВременноеХранилище(Неопределено, Новый УникальныйИдентификатор()));
	СтруктураПараметров.Вставить("СопровождающийТекст",				НСтр("ru = 'Выполняется загрузка курсов валют...'"));
	//СтруктураПараметров.Вставить("СписокВалют",						ПолучитьАдресТаблицыВалют());
	СтруктураПараметров.Вставить("СписокВалют",						ТекущийСписокВалют);
	СтруктураПараметров.Вставить("НачалоПериода",					Объект.НачалоПериода);
	СтруктураПараметров.Вставить("ОкончаниеПериода",				Объект.ОкончаниеПериода);
	
	
	НаименованиеЗадания = НСтр("ru = 'Длительная операция внешней обработки'");
	
	ВыполняемыйМетод = "ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки";
	
	ПараметрыЗадания = Новый Структура;
	ПараметрыЗадания.Вставить("ИмяОбработки", АдресФайлаНаСервере);
	ПараметрыЗадания.Вставить("ИмяМетода", "ВыполнитьКоманду");
	ПараметрыЗадания.Вставить("ПараметрыВыполнения", СтруктураПараметров);
	ПараметрыЗадания.Вставить("ЭтоВнешняяОбработка", Истина);
	ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка",Неопределено);
	//ПараметрыЗадания.Вставить("ДополнительнаяОбработкаСсылка", Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("Длительная операция"));
	
	ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
	ПараметрыВыполнения.НаименованиеФоновогоЗадания = НаименованиеЗадания;
	
	РезультатФоновогоЗадания = ДлительныеОперации.ЗапуститьВыполнениеВФоне(УникальныйИдентификатор, ВыполняемыйМетод, ПараметрыЗадания, ПараметрыВыполнения);
	
	ИдентификаторЗадания = РезультатФоновогоЗадания.ИдентификаторЗадания;
	
КонецПроцедуры

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

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

Нужно еще назначить "имя файла" или на форме указывать, решил просто переменной записать.
ПараметрыЗадания.Вставить("ИмяМетода", 

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

	Возврат Результат;
КонецФункции
Показать


В итоге что-то и вышло, но толку ноль.
По https://infostart.ru/public/525648/ уже писал обработку. Результат есть, но прогресса нет.
compaud; Franchiser; +2 Ответить
12. nikita0832 170 08.10.18 09:35 Сейчас в теме
(11)Да, ПрогрессОбработки и ИдентификаторЗадания надо добавлять на форму, это стоило указать хотя мне и казалось чем-то само собой разумеющимся. Имя файла проще всего получить через функцию
РеквизитФормыВЗначение("Объект").ИспользуемоеИмяФайла;

Ошибка при сохранении связана с безопасным режимом, если у Вас полные права, то такой проблемы не возникает.
Чтобы не выводить прогресс через состояние для ПрогрессОбработки сделайте Элемент с видом Поле индикатора. СтруктураПараметров - понятное дело ваша, там параметры для процедуры, которую будем запускать. Для простоты можно сделать просто процедуру типа
Процедура ДлительнаяОперация(Параметры)
Выполнить(Параметры.Код);
КонецПроцедуры

и на самой форме
СтруктураПараметров = Новый Структура("Код",Код); //Код из реквизита формы

но это совсем упрощенно
13. Xershi 512 21.10.18 00:24 Сейчас в теме
(12) выход вывод прогресса это не типовой функционал БСП, а нарисованная форма / элемент в обработке. Плюс как я понял нужно делать в логике длительной операции вызов процедуры:
ДлительныеОперации.СообщитьПрогресс(Окр(ПроцентВыполнения, 0), Описание);

В которую и передавать процент выполнения, а далее обработчик ожидания, его прочитает и вставит в наш реквизит.
16. Franchiser 47 31.10.18 12:31 Сейчас в теме
(11) для чего проверяется сообщение на фигурную скобку?
17. Xershi 512 31.10.18 13:44 Сейчас в теме
(16) когда длительная операция возвращает результат, то он в хмл, вот автор это и проверяет!
14. Franchiser 47 31.10.18 12:13 Сейчас в теме
Если на форме обработки идёт прогресс, у тебя остаются кликабельными кнопки и остаётся возможность менять реквизиты у пользователя в процессе выполнения длительной операции, или ты это запрещаешь?
18. nikita0832 170 03.11.18 00:41 Сейчас в теме
(14) менять реквизиты на ходу не получится, только перезапускать сеанс или мутить хранилище со значениями реквизитов и получать их в цикле. Тут надо понимать, что выполнение кода - это уже отдельный сеанс, основной сеанс о нем знает по идентификатору, а второй сеанс о первом не знает впринципе. Как я уже говорил пример где это работает здесь: https://infostart.ru/public/585055/ кода много в итоге, не уверен что Вам все нужно.
20. Franchiser 47 03.11.18 01:32 Сейчас в теме
(18) речь не об этом, я не понимаю почему выбраеа такая технология : размещать прогресс на той же форме, а не открывать отдельную как в бсп.
В этом случае же есть недостатки:
1. Нужно постоянно во все свои доработки вносить намыорму прогресс и код для фонового задания
2. Когда пользователь запустил длительный процесс, он может в форме продолжать что-то творить , т.к. она осталась не заблокированной.

Мне кажется удобнее когда форма прогресса открывактся отдельно с блокированием прогоесса.
P.s. Обработку посмотреть не могу, нет см.
21. nikita0832 170 03.11.18 22:50 Сейчас в теме
(20) нет особых проблем с тем чтобы заблокировать форму, это уже по желанию Доступность = ложь; для всех элементов кроме кнопок управления внешним процессом. Вообще идея в том чтобы код можно было вписывать в текстовое поле или например хранить в файлах, то есть обработка одна, а вариантов запускаемого кода много.
15. Franchiser 47 31.10.18 12:15 Сейчас в теме
До конца не понятно какие процедуры используются, т.к. указаны части кода из процедур, можешь привести код всех процедур полностью?
22. compaud 08.11.18 16:44 Сейчас в теме
Что то я не понял что и как нужно сделать.

Я хочу сформировать табличный документ. Каждая строчка которого долго делается.

В одной обработке в модуле объекта я пишу

Процедура ДлительнаяОперация() ЭКСПОРТ
	
	Дата = ТекущаяДата();
	
	Пока Дата <= Дата+60000 Цикл
		Сообщить(ТекущаяДата());
	КонецЦикла;
	
	
КонецПроцедуры
Показать


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

Потом я делаю еще 1 обработку:

&НаКлиенте
Процедура Сформировать(Команда)
	СформироватьнаСервере();	
	
	ПодключитьОбработчикОжидания("ПроверкаФоновогоЗадания",1,Ложь);
	
	
	
КонецПроцедуры


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


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

&НаКлиенте
Процедура УбитьПроцесс(Команда)
	
	УбитьПроцессНаСервере();
	ОтключитьОбработчикОжидания("ПроверкаФоновогоЗадания");
	Сообщить(""+ТекущаяДата()+" задание выполнено");
	
КонецПроцедуры
Функция ПроверкаФоновогоЗаданияНаСервере()
	Рез = Новый Структура("Прогресс,Состояние");
		
	Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
	ЗаполнитьЗначенияСвойств(Рез,Задание);
	Рез.Состояние= СТрока(Рез.Состояние);
	Если Задание = Неопределено Тогда
		Возврат Неопределено;
	Иначе
		
		Сообщения=Задание.ПолучитьСообщенияПользователю(Ложь);
		Для Каждого Сообщение ИЗ Сообщения Цикл
			Если Лев(Сообщение.Текст,1) <> "{" Тогда
				Сообщить(Сообщение.Текст);
			КонецЕсли;
		КонецЦикла;
		Прогресс = ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
		Если Прогресс <> Неопределено Тогда
			ПрогрессОбработки = Прогресс.Процент;//?(Прогресс.Процент<>0,Прогресс.Процент,ПрогрессОбработки);
		КонецЕсли;
		Рез.Вставить("Прогресс",Прогресс);
	КонецЕсли;

	Возврат Рез;
КонецФункции

&НаСервере
Процедура УбитьПроцессНаСервере()
	Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
	Задание.Отменить();
//	Элементы.ГруппаФоновоеЗадание.Видимость=Ложь;
КонецПроцедуры
Показать


На форме 2 обработки создал реквизит ИдентификаторЗадания типа УникальныйИдентификатор

Ну и ничего не работает.

Какой нибудь пример бы чистый.
И я не понимаю еще вот что, этот код опрашивает 1 раз фоновое задание. О каком статус баре идет речь не пойму. Сложно в общем что то
23. vadim1011985 60 08.11.18 17:03 Сейчас в теме
(22) У Вас дополнительная внешняя обработка ?
24. compaud 09.11.18 09:10 Сейчас в теме
(23) да, в этом и смысл. В одну все поместить так понимаю нельзя. Ну хоть в 2
25. vadim1011985 60 09.11.18 10:01 Сейчас в теме
Почему нельзя ? Все можно . Вам просто надо все сделать правильно.
1) добавить 2 ключевых параметра Идентификатор команды - тип строка и ДополнительнаяОбработкаСсылка с типом Справочник ссылка Дополительные внешние отчеты и обработки
2) в модуле формы создать команду которая будет запускать длительную операцию ( но это не сама длительная операция ) см мой 19 ответ в этой теме процедура ЗагрузитьИЗаписать только надо будет заменит ВыполнитьКомандуВФоне на ДлительныеОперацииКлиент.ВыполнитьКомандуВФоне

3) В модуле объекта пишешь функцию регистрации внешней обработки (сведения о внешней обработке )
И добавляешь процедуру ВыполнитьКоманду ( ИдентификаторКоманды,Параметрывыполнения) - тут могу ошибиться как звучит второй параметр , в которой реализуешь свою длительную операцию

Вот и все
26. nikita0832 170 09.11.18 12:32 Сейчас в теме
(25) Зачем регистрировать? то есть можно и регистрировать, но идея в том что БСП-шная процедура ДлительныеОперации.ВыполнитьПроцедуруМодуляОбъектаОбработки открывает обработку просто как внешний файл и выполняет экспортную процедуру из её модуля. Команда здесь тоже не нужна, хотя наверное и через неё можно.
27. vadim1011985 60 09.11.18 12:39 Сейчас в теме
(26) я описал типовой механизм вызова длительной операции из внешней обработки как это рекомендует 1с.

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

Плюс вам писали про стандартные методы БСП и Вы сказали что Вам не нравится что нет идентификатора задания и котик вам не нравится и хотелось бы получать прогресс , но как я Вам уже отвечал это все решаемо , как раз Ваша статья на ряду с другими на эту тему натолкнула меня на мысль написать свою хотя она повторят то чт оо чем я писал тут выше
28. victorkim64 84 30.01.19 02:37 Сейчас в теме
Спасибо! Разобрался, использую
Оставьте свое сообщение