Задержки в работе функции ПоместитьВоВременноеХранилище

 В платформе версией до 8.3.9.1818 для обычных форм существует следующая ошибка:

   Строка "ПоместитьВоВременноеХранилище(Данные, АдресХранилища);" выполняется мгновенно, но сам результат может быть помещен во временное хранилище со значительной задержкой. В статье описан простой вариант обхода данной ошибки.

   Периодически результат выполнения фонового задания долго помещается во временное хранилище, при этом само фоновое задание уже не активно. Найденные способы решения: переписать на управляемых формах, обновить платформу, использовать общую форму "ДлительнаяОперация" из БСП. Если описанные решения не подходят, то существует ещё один вариант (упоминаний о нём не нашел).
   Рассмотрим следующий пример - в конфигурации присутствует отчёт, часть данных для которого формируется в фоновом задании. Стандартно в форме отчёта запускается обработчик ожидания, в котором проверяется состояние фонового задания. При успешном завершении по адресу временного хранилища должны быть данные с результатом работы задания, но "появиться" они там могут с задержкой. Для решения проблемы можно передать представление результата работы задания в тексте сообщения (используя функцию ЗначениеВСтрокуВнутр).

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

Если знаете другие варианты борьбы с данной ошибкой - просьба написать в комментариях.

UPD: баг периодически оживает (пример1, детальнее на партнерском форуме).














Комментариев нет:

Отправить комментарий