Длительные операции на сервере. Часть 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. Обработка результата выполнения фонового задания.
&НаКлиенте
Процедура ПриЗавершенииПоискаНастроек(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда // Пользователь отменил задание.
Возврат;
КонецЕсли;
Если Результат.Статус = "Ошибка" Тогда
ВызватьИсключение Результат.КраткоеПредставлениеОшибки;
КонецЕсли;
Настройки = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
УстановитьНастройкиУчетнойЗаписи(Настройки);
КонецПроцедуры См. также