Длительные операции на сервере. Часть 1
Библиотека стандартных подсистем 3.0
Разработчики платформы 1С: предприятие 8.3 рекомендуют в управляемых приложениях избегать длительных вызовов из клиентского кода в серверный. Они считают, что все длительные серверные вызовы, которые могут выполняться более 8 секунд в обычных сценариях работы пользователя, следует выполнять асинхронно, с помощью фонового задания.
В демоверсии БСП 3.0 разработана демонстрационная обработка _ДемоДлительнаяОперация , позволяющая понять общий подход к асинхронному выполнению длительных серверных операций с помощью фонового задания:
Интерфейс обработки вылядит так:
Процедура ВыполнитьДействие(Параметры, АдресРезультата) ЭкспортОбщегоНазначения.СообщитьПользователю(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = '%1 Выполняется действие %2'"), ТекущаяДатаСеанса(), Параметры.НомерОперации));
Если Не Параметры.ВыполнитьСразу Тогда
Начало = ТекущаяДатаСеанса();
Длительность = 20; // 20 секунд
СрокЗавершения = Начало + Длительность;
ПредыдущийИндекс = 0;
Пока ТекущаяДатаСеанса() < СрокЗавершения Цикл
Индекс = ТекущаяДатаСеанса() - Начало;
Если Индекс <> ПредыдущийИндекс Тогда
ПредыдущийИндекс = Индекс;
Процент = Макс(Цел(Индекс * 100 / Длительность), 1);
Этап = Цел(Процент / Длительность) + 1;
ОбщегоНазначения.СообщитьПользователю(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 операция %2 выполнена на %3 % (этап %4)'"),ТекущаяДатаСеанса(), Параметры.НомерОперации, Процент, Этап));
Если Параметры.ВыводитьПрогрессВыполнения Тогда
ДлительныеОперации.СообщитьПрогресс(Процент, СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Этап %1'"), Этап));
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецЕсли;
Если Параметры.ОжидаемыйРезультат = "Успешно"
Тогда
ПоместитьВоВременноеХранилище(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Действие %1 успешно выполнено.'"), Параметры.НомерОперации), АдресРезультата);
ИначеЕсли Параметры.ОжидаемыйРезультат = "Ошибка" Тогда
ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Ошибка: действие %1 не выполнено'"), Параметры.НомерОперации);
КонецЕсли;
КонецПроцедуры
Следует отметить, что если код, выполняющий длительную обработку данных расположить в общем модуле , а не в модуле менеджера , то необходимо использовать процедуру-обертку в общем модуле, которая будет вызывать процедуру модуля менеджера через ОбщегоНазначения.ВыполнитьМетодКонфигурации(). Т.к. фоновые задания могут работать только с процедурами и функциями общих модулей, например,
ОбщегоНазначения.ВыполнитьМетодКонфигурации(Обработчик, ПараметрыОбработчика);
В библиотеке стандартных подсистем многие длительные операции расположены в общем модуле. Путем глобального поиска процедуры ОбщегоНазначения.ВыполнитьМетодКонфигурации() можно посмотреть программный код.
Для выполнения кода длительной обработки данных на сервере запускается фоновое задание, при этом необходимо ожидать завершения выполнения фонового задания в течение 0.8 сек. Вот пример программного кода действия кнопки “Выполнить действие” демообработки:
&НаКлиенте Процедура ВыполнитьДействие(Команда)ПередВыполнением();
Если (ПрогрессВыполнения Или ВыводитьСообщения) И (ФормаОжидания <> "Показывать") Тогда
ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ВыполнитьДействиеПрогрессВыполнения", ЭтотОбъект);
Иначе
ОповещениеОПрогрессеВыполнения = Неопределено;
КонецЕсли;
ДлительнаяОперация = НачатьВыполнениеНаСервере(НомерОперации);
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ПараметрыОжидания.ТекстСообщения = Уведомление;
ПараметрыОжидания.ВыводитьПрогрессВыполнения = ПрогрессВыполнения;
ПараметрыОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения;
ПараметрыОжидания.ОповещениеПользователя.Показать = Истина;
ПараметрыОжидания.ОповещениеПользователя.НавигационнаяСсылка = "e1cib/app/Обработка._ДемоДлительнаяОперация";
ПараметрыОжидания.ВыводитьОкноОжидания = (ФормаОжидания = "Показывать");
ПараметрыОжидания.ВыводитьСообщения = ВыводитьСообщения;
ОповещениеОЗавершении = Новый ОписаниеОповещения("ВыполнитьДействиеЗавершение", ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания);
КонецПроцедуры
Обратите внимание, что вызов длительной обработки данных происходит асинхронно, с помощью объекта описания оповещения .
В теле процедуры ВыполнитьДействиеЗавершение выводится результат, который получается из временного хранилища. Иными словами, при получении от сервера информации о том, что фоновое задание завершено, полученный результат загружается из временного хранилища и обрабатывается.
&НаКлиенте Процедура ВыполнитьДействиеЗавершение(Результат, ДополнительныеПараметры) ЭкспортЭлементы.Страницы.ТекущаяСтраница = Элементы.СтраницаУведомление;
Если Результат = Неопределено Тогда
// отменено пользователем
Возврат;
КонецЕсли;
ВывестиРезультат(Результат);
Если Результат.Статус = "Ошибка" Тогда
ПоказатьПредупреждение(,Результат.КраткоеПредставлениеОшибки); КонецЕсли;
КонецПроцедуры &НаСервере Процедура ВывестиРезультат(Результат)Если Результат.Статус = "Выполнено" Тогда
ТекстСообщения = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
ИначеЕсли Результат.Статус = "Ошибка" Тогда
ТекстСообщения = Результат.ПодробноеПредставлениеОшибки;
КонецЕсли;
Если Результат.Сообщения <> Неопределено Тогда
Для каждого СообщениеПользователю Из Результат.Сообщения Цикл
СообщениеПользователю.Сообщить();
КонецЦикла;
КонецЕсли; ОбщегоНазначения.СообщитьПользователю(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 %2'"), ТекущаяДатаСеанса(), ТекстСообщения));
КонецПроцедуры
Следует отметить, что асинхронное выполнение длительных серверных операций рекомендуется выполнять при формировании отчетов, которых, как правило, занимает длительное время.
Вернемся теперь к программному коду в модуле менеджера в начале статьи. Обратите внимание, что поведение процедуры зависит от переданных параметров. На время выполнения выдается сообщение :
ОбщегоНазначения.СообщитьПользователю(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтрку( НСтр("ru = '%1 Выполняется действие %2'"), ТекущаяДатаСеанса(), Параметры.НомерОперации));
Если выбрать скорость выполнения с задержкой, обрабатывается демонстрационный цикл из 20 итераций для эмуляции выполнения длительной операции. На время выполнения этого цикла пользователю отображается индикатор:
Если за время ожидания выполнения длительного задания оно не завершилось, то управление возвращается на клиент, и в клиентском коде подключается обработчик ожидания, в котором периодически проверяется состояние фонового задания. При этом интервал опроса задания увеличивается от 1 до 15 секунд с фиксированным коэффициентом 1.4;
В Библиотеке стандартных подсистем имеются вспомогательные функции и процедуры в общих модулей :
- ДлительныеОперации
- ДлительныеОперацииКлиент
Все эти функции и процедуры содержат в заголовке краткое описание их назначений.
Практический пример
Практический пример выполнения функции в фоновом задании в конфигурации библиотеки стандартных подсистем можно найти в модуле менеджера спраочника Учетные записи электронной почты. Там расположена функция, которая выполняет поиск настроек и возвращает их:
Функция ОпределитьНастройкиУчетнойЗаписи(АдресЭлектроннойПочты, Пароль) Экспорт
...
Возврат Настройки;
КонецФункции очень сложный для описани здесь
В форме справочника Учетные записи электронной почты выполняется вызов этой функции в фоновом задании в три этапа:
- запуск фонового задания на сервере,
- подключение обработчика завершения фонового задания на клиенте,
- обработка результата выполнения фонового задания.
&НаКлиенте Процедура НастроитьПараметрыПодключенияАвтоматически() // 1. Запуск фонового задания на сервере. ДлительнаяОперация = НачатьПоискНастроекУчетнойЗаписи(); // 2. Подключение обработчика завершения фонового задания. ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект); Оповещение = Новый ОписаниеОповещения("ПриЗавершенииПоискаНастроек", ЭтотОбъект); ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, Оповещение, ПараметрыОжидания); КонецПроцедуры &НаСервере Функция НачатьПоискНастроекУчетнойЗаписи() ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор); Возврат ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, "Справочники.УчетныеЗаписиЭлектроннойПочты.ОпределитьНастройкиУчетнойЗаписи", АдресЭлектроннойПочты, Пароль); КонецФункции // 3. Обработка результата выполнения фонового задания. &НаКлиенте Процедура ПриЗавершенииПоискаНастроек(Результат, ДополнительныеПараметры) Экспорт Если Результат = Неопределено Тогда // Пользователь отменил задание. Возврат; КонецЕсли; Если Результат.Статус = "Ошибка" Тогда ВызватьИсключение Результат.КраткоеПредставлениеОшибки; КонецЕсли; Настройки = ПолучитьИзВременногоХранилища(Результат.АдресРезультата); УстановитьНастройкиУчетнойЗаписи(Настройки); КонецПроцедуры
См. также