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