Как правильно передать результат выполнения фонового задания через временное хранилище в 1С 8.3

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке в среде «1С:Предприятие 8.3» одной из частых задач является перенос ресурсоемких операций в фоновый режим. Это позволяет сохранить интерфейс программы отзывчивым для пользователя. Однако на этапе получения результатов выполнения фонового задания разработчики часто сталкиваются с неприятной проблемой: данные, успешно помещенные во временное хранилище на сервере, при попытке прочитать их на клиенте возвращают Неопределено. В этой статье мы подробно разберем механизм взаимодействия фоновых заданий с временным хранилищем, выясним причины возникновения этой ошибки и рассмотрим правильные архитектурные решения.

Суть проблемы: почему возвращается Неопределено?

Рассмотрим типичную ситуацию. Нам необходимо асинхронно получить тяжелые двоичные данные из внешнего источника (например, запросить файлы логов, данные с приборов или сетевых камер) и отобразить их на форме. Мы запускаем фоновое задание, внутри которого происходит обращение к внешнему сервису. Полученные двоичные данные мы помещаем во временное хранилище и передаем адрес обратно на форму. Но при попытке прочитать данные по этому адресу на клиенте мы получаем пустоту.

Основная причина кроется в **изоляции сеансов**. Нам необходимо четко понимать, как платформа разделяет контексты выполнения обычных клиентских вызовов и фоновых процессов.

Механизм работы временного хранилища в фоновых заданиях

Фоновое задание в «1С:Предприятие» всегда выполняется в своем **собственном, изолированном сеансе**. Временное хранилище, в свою очередь, неразрывно связано с сеансом, в котором оно было создано.

Если мы вызываем метод ПоместитьВоВременноеХранилище(Данные) без указания конкретного адреса и без привязки к уникальному идентификатору формы родительского сеанса, платформа создает новый адрес в рамках сеанса фонового задания. Как только фоновое задание успешно или аварийно завершает свою работу, его сеанс закрывается и уничтожается. Вместе с сеансом фонового задания безвозвратно удаляются и все созданные в нем временные хранилища. Именно поэтому на клиенте по сохраненным адресам считывается Неопределено.

Чтобы данные успешно «перекочевали» из изолированного сеанса фонового задания в родительский сеанс пользователя, необходимо соблюдать строгое платформенное правило переноса данных.

Анализ ошибочного кода

Проанализируем фрагмент кода, который приводит к ошибке:


// Внутри фонового задания
АдресДанных = Неопределено;
ДвоичныеДанные = Ответ.ПолучитьТелоКакДвоичныеДанные();
АдресДанных = ПоместитьВоВременноеХранилище(ДвоичныеДанные, АдресДанных);
ВходныеПараметры["АдресДанных1"] = АдресДанных;

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

Правильный алгоритм передачи данных

Для того чтобы передать результаты работы фонового задания обратно в форму, нам необходимо выполнить следующие шаги:

  1. Инициализировать адрес в родительском сеансе: Перед запуском фонового задания, на клиенте или сервере в контексте формы, мы должны создать «пустышку» во временном хранилище, обязательно связав её с уникальным идентификатором формы.
  2. Передать готовый адрес в фоновое задание: Этот зарезервированный адрес передается в фоновое задание в качестве одного из параметров запуска.
  3. Записать данные по переданному адресу: Внутри фонового задания мы помещаем результат строго по этому адресу.

При таком подходе платформа 1С автоматически скопирует данные из временного хранилища фонового сеанса в хранилище родительского сеанса в момент успешного завершения фонового задания.

Вариант 1. Предварительное резервирование адреса в родительском сеансе

Давайте рассмотрим, как реализовать этот алгоритм на практике. Ниже представлен корректный шаблон кода для работы с фоновым заданием.

Код модуля управляемой формы:


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    // Шаг 1: Инициализируем адрес-пустышку в контексте нашей формы
    АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, ЭтаФорма.УникальныйИдентификатор);
    
    // Шаг 2: Запускаем фоновое задание, передавая зарезервированный адрес
    ЗапуститьПолучениеДанныхВФоне(АдресРезультата);
    
    // Подключаем обработчик ожидания для проверки статуса выполнения
    ПодключитьОбработчикОжидания("Подключаемый_ПроверитьВыполнениеЗадания", 2);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура ЗапуститьПолучениеДанныхВФоне(Знач АдресРезультата)
    ПараметрыПроцедуры = Новый Массив;
    ПараметрыПроцедуры.Добавить(АдресРезультата);
    
    // Выполняем экспортную процедуру в фоновом режиме
    ФоновыеЗадания.Выполнить("ОбщийМодульСервер.ПолучитьДанныеОборудования", ПараметрыПроцедуры);
КонецПроцедуры

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

Код в общем модуле (серверном):


Процедура ПолучитьДанныеОборудования(АдресРезультата) Экспорт
    // Выполняем тяжелую операцию получения данных
    ДвоичныеДанные = ПолучитьДанныеИзВнешнегоИсточника();
    
    // Шаг 3: Помещаем результат строго по переданному адресу родительского сеанса
    ПоместитьВоВременноеХранилище(ДвоичныеДанные, АдресРезультата);
КонецПроцедуры

Вариант 2. Использование структуры для упаковки нескольких файлов

Что делать, если фоновое задание должно вернуть не один файл, а сразу несколько (например, пакет из четырех файлов данных)? Создавать под каждый файл свой адрес в родительском сеансе неудобно.

В этом случае наиболее красивым и производительным решением будет упаковка всех результатов в единую структуру прямо внутри фонового задания. Мы передаем в фоновое задание один-единственный адрес, а на выходе получаем структуру, содержащую все необходимые двоичные данные.

Проанализируем, как изменится серверная процедура:


Процедура ПолучитьПакетДанных(АдресРезультата) Экспорт
    // Создаем структуру для хранения пакета результатов
    ПакетДанных = Новый Структура;
    
    Для Индекс = 1 По 4 Цикл
        ДвоичныеДанные = ПолучитьФайлСУстройства(Индекс);
        ПакетДанных.Вставить("Данные_" + Индекс, ДвоичныеДанные);
    КонецЦикла;
    
    // Помещаем всю структуру в один зарезервированный адрес
    ПоместитьВоВременноеХранилище(ПакетДанных, АдресРезультата);
КонецПроцедуры

После завершения задания на клиенте мы считываем структуру целиком и легко распределяем ее элементы по нужным реквизитам формы:


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

Современный стандарт разработки с использованием БСП

В современных конфигурациях, использующих Библиотеку Стандартных Подсистем (БСП), разработчики редко используют вызов ФоновыеЗадания.Выполнить напрямую. Вместо этого применяется готовый инструментарий подсистемы «Длительные операции».

БСП берет на себя всю рутину по выделению адресов во временном хранилище и отслеживанию жизненного цикла заданий. Мы можем использовать метод ДлительныеОперации.ЗапуститьВыполнениеВФоне. БСП автоматически резервирует адрес для хранения результата выполнения операции и возвращает его в структуре параметров запуска.

Рассмотрим пример запуска фонового задания по стандартам БСП:


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

Внутри выполняемой процедуры ВыполнитьТяжелуюОперацию нам достаточно передать полученные результаты в адрес временного хранилища, который БСП автоматически добавит в параметры вызова. На клиенте мы используем метод ДлительныеОперацииКлиент.ОжидатьЗавершение, который самостоятельно вернет нам готовый адрес с результатами по окончании работы фонового задания.

Важные нюансы производительности и очистки памяти

При активном использовании временного хранилища для передачи больших объемов двоичных данных (особенно при постоянном циклическом опросе внешних систем) необходимо учитывать следующие аспекты:

Применяя эти правила и понимая специфику изоляции сеансов фоновых заданий, вы навсегда избавитесь от ошибок получения пустых значений и обеспечите быструю, стабильную работу ваших механизмов асинхронной обработки данных.

← На главную