Добрый день.
Недавно возникла необходимость задействовать механизм фоновых операций в самописанной (не мной) конфигурации без БСП. Требовалось некоторые операции, которые пользователь запускает вручную, сделать выполняемыми в фоне. В основном, необходимо было получить состояние выполнения – успешно или с ошибкой. В платформе 8.3.26 это решилось с помощью механизма «УведомленияКлиента». Механизм простой, пояснений не требует.
Но в одной задаче требовалась индикация выполнения задачи. И задача эта – загрузка курсов валют. Пользователь может выбрать любые валюты для загрузки и любой период. Во время загрузки курсов интерфейс не должен подвисать, должен быть виден процесс загрузки, пользователь может продолжать работать с другими документами.
Много подробной информации о запуске фоновых операций с помощью БСП, а вот в информации о штатных средствах много неточностей, пропусков некоторых моментов. Возможно, мне попадалась не та информация и не в том месте.
В общем, для моего случая, все оказалось просто. Даже проще, чем с помощью БСП. Обобщив всю информацию, решил написать шпаргалку.
Для статьи из кода выкинул все побочное, оставил только самое необходимое.
Все действия по запуску и выводу индикации происходят в модуле общей формы. Загрузка курсов осуществляется с сервера Нацбанка Республики Беларусь по API.
ИдентификаторЗадания – реквизит формы тип Уникальный идентификатор
Прогресс – реквизит формы тип Число Длина 3 Точность 0
1. Команда запуска фоновой процедуры
&НаКлиенте
Процедура ЗагрузитьКурсы(Команда)
СоответствиеВалют = СписокВалютДляЗагрузкиКурсов();
ДатыЗагрузкиКурсов = ДатыЗагрузкиКурсов();
Элементы.ПрогрессБар.Видимость = ДатыЗагрузкиКурсов.Количество() > 15;
Прогресс = 0;
Элементы.ДекорацияДатаЗагрузки.Заголовок = "";
ИдентификаторЗадания = ЗагрузитьКурсыНаСервереФоновоеЗадание(СоответствиеВалют, ДатыЗагрузкиКурсов);
ПодключитьОбработчикОжидания("ОбработчикЗагрузкиКурсовЗаПериод", 1);
КонецПроцедуры
Здесь все понятно. Клиентскими функциями формируются параметры для фоновой процедуры. Соответствие «СоответствиеВалют» со списком валют и массив «ДатыЗагрузкиКурсов». Прогресс бар виден пользователю, если количество дат для загрузки больше 15, иначе он просто не успевает отрабатывать. «ДекорацияДатаЗагрузки» используется для вывода дат загрузки курсов. На форме еще расположена стандартная анимация длительной операции. Дальше вызывается серверная функция запускающая фоновое задание и возвращающая идентификатор задания.Далее подключается обработчик ожидания с периодом вызова 1 секунда. В процедуре вызываемой обработчиком будет осуществляться формирование индикации пользователю.
2. Функция запуска фонового задания
&НаСервере
Функция ЗагрузитьКурсыНаСервереФоновоеЗадание(СоответствиеВалют, ДатыЗагрузкиКурсов)
ПараметрыВыполнения = Новый Массив();
ПараметрыВыполнения.Добавить(СоответствиеВалют);
ПараметрыВыполнения.Добавить(ДатыЗагрузкиКурсов);
ИмяПроцедуры = "РаботаСКурсамиВалют.ЗагрузитьКурсыВалютРБЗаПериод";
КлючЗадания = Новый УникальныйИдентификатор();
Задание = ФоновыеЗадания.Выполнить(ИмяПроцедуры, ПараметрыВыполнения, КлючЗадания, "Загрузка курсов валют");
Возврат Задание.УникальныйИдентификатор;
КонецФункции
Здесь формируется массив «ПараметыВыполнения». Цитата из Синтаксис помощника (МенеджерФоновыхЗаданий -> Выполнить())
- Массив параметров, передаваемых в метод. Количество и типы параметров должны соответствовать параметрам метода. Все передаваемые параметры должны поддерживать сериализацию. В противном случае будет выдано исключение и фоновое задание не будет запущено.
«ИмяПроцедуры». Опять цитата - Имя экспортируемой процедуры или функции неглобального общего модуля, который может быть выполнен на сервере, в форме ИмяМодуля.ИмяМетода.
«КлючЗадания» - использую уникальный идентификатор.
Запускается фоновое задание и возвращается уникальный идентификатор фонового задания. Четвёртый параметр в запуске фонового задания является описанием и необязателен.
3. Функция поиска фонового задания по идентификатору задания
&НаСервереБезКонтекста
Функция НайтиФоновоеЗаданиеПоИдентификатору(ИдентификаторЗадания)
РезультатПоиска = Новый Структура("Состояние, ИнформацияОбОшибке, МассивСообщений", Истина, "");
НайденноеЗадание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
Если НайденноеЗадание.Состояние = СостояниеФоновогоЗадания.Завершено Тогда
РезультатПоиска.Состояние = Ложь;
ИначеЕсли НайденноеЗадание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда
РезультатПоиска.Состояние = Ложь;
РезультатПоиска.ИнформацияОбОшибке = НайденноеЗадание.ИнформацияОбОшибке.Причина.Описание;
ИначеЕсли НайденноеЗадание.Состояние = СостояниеФоновогоЗадания.Отменено Тогда
РезультатПоиска.Состояние = Ложь;
РезультатПоиска.ИнформацияОбОшибке = "Отменено";
КонецЕсли;
РезультатПоиска.МассивСообщений = НайденноеЗадание.ПолучитьСообщенияПользователю(Истина);
Возврат РезультатПоиска;
КонецФункции
Выполняется на сервере без контекста. Получает на вход один параметр – «ИдентификаторЗадания».
Сразу создаётся структура, для возврата из функции. Значение ключей «Состояние» по умолчанию Истина, «ИнформацияОбОшибке» пустая строка.
Ищется фоновое задание по идентификатору и в зависимости от состояния фонового задания (если фоновое задание завершено по какой либо причине) ключам структуры «Состояние» и «ИнформацияОбОшибке» присваиваются значения.
Получаются сообщения пользователю сформированные в фоновом задании с удалением старых сообщений.
4. Вспомогательная функция для разделения строки сообщения
&НаКлиенте
Функция РазделитьТекстСообщения(ТекстСообщения)
Результат = Новый Структура("ДатаЗагрузки, ПроцентВыполнения");
СтрокиСообщения = СтрРазделить(ТекстСообщения, ";");
Результат.ДатаЗагрузки = СтрокиСообщения[0];
Результат.ПроцентВыполнения = Число(СтрокиСообщения[1]);
Возврат Результат;
КонецФункции
Сама строка сообщения формируется из двух строк в процедуре запущенной в фоне в виде
ПроцентТекст = ПроцентВыполнения(ВсегоЗаписей, ТекущаяЗапись);
ДатаЗагрузкиТекст = Формат(ДатаКурса, "ДФ=dd.MM.yyyy");
Сообщить(ДатаЗагрузкиТекст + ";" + ПроцентТекст);
Т.е. содержит в себе Дату загрузки курса и процент выполнения. Разделитель строк ;.
5. И сама процедура, вызываемая из обработчика ожидания
&НаКлиенте
Процедура ОбработчикЗагрузкиКурсовЗаПериод()
РезультатПоиска = НайтиФоновоеЗаданиеПоИдентификатору(ИдентификаторЗадания);
Если РезультатПоиска.Состояние Тогда
Если РезультатПоиска.МассивСообщений.Количество() > 0 Тогда
МаксимальныйИндекс = РезультатПоиска.МассивСообщений.ВГраница();
СообщениеПользователю = РазделитьТекстСообщения(РезультатПоиска.МассивСообщений[МаксимальныйИндекс].Текст);
Элементы.ДекорацияДатаЗагрузки.Заголовок = "Загружены курсы на дату " + СообщениеПользователю.ДатаЗагрузки;
Прогресс = СообщениеПользователю.ПроцентВыполнения;
КонецЕсли;
Возврат;
КонецЕсли;
Если НЕ РезультатПоиска.Состояние Тогда
ОтключитьОбработчикОжидания("ОбработчикЗагрузкиКурсовЗаПериод");
Если РезультатПоиска.ИнформацияОбОшибке = "" Тогда
//ОповеститьОбОкончанииЗагрузки();
ОповеститьОбИзменении(Тип("РегистрСведенийКлючЗаписи.КурсыВалют"));
Иначе
ТекстПредупреждения = "Не удалось загрузить курсы валют по причине - " +
РезультатПоиска.ИнформацияОбОшибке;
ПоказатьПредупреждение(, ТекстПредупреждения, 0, "Ошибка загрузки курсов валют");
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Вызывается функция из пункта 3, которая возвращает структуру, содержащую состояние фонового задания, сообщение об ошибке и массив сообщений пользователю.
Если фоновое задание активно, то из массива сообщений берётся последняя запись и пользователю показывается дата загрузки курса и процент выполнения.
Если фоновое задание завершено, то отключается обработчик ожидания и проверяется сообщение об ошибке. Если пустое, то выводится оповещение о успешной загрузке, если не пустое, то выводится предупреждение пользователю с текстом ошибки.
Еще раз повторюсь, что код по работе с формой с формой я убрал, оставил только основное.
Получилось довольно просто. Если не нужно отслеживать процесс выполнения задания, то можно остановиться на пункте 2.
Подозреваю, что БСП работает по схожему принципу с фоновыми заданиями.
Тестировал на платформе 8.3.26.1540.