Длительные операции на сервере. Часть 1

Печать (Ctrl+P)

Библиотека стандартных подсистем 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. обработка результата выполнения фонового задания.
 &НаКлиенте
Процедура НастроитьПараметрыПодключенияАвтоматически()
 // 1. Запуск фонового задания на сервере.
 
ДлительнаяОперация = НачатьПоискНастроекУчетнойЗаписи();
 
 // 2. Подключение обработчика завершения фонового задания.

 ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
 Оповещение = Новый ОписаниеОповещения("ПриЗавершенииПоискаНастроек", ЭтотОбъект);
 ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, Оповещение, ПараметрыОжидания);
КонецПроцедуры

&НаСервере
Функция НачатьПоискНастроекУчетнойЗаписи()
 ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
 Возврат ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, "Справочники.УчетныеЗаписиЭлектроннойПочты.ОпределитьНастройкиУчетнойЗаписи",
  АдресЭлектроннойПочты, Пароль);
КонецФункции

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

См. также

Previous Article
Next Article

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.