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

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

При разработке на платформе 1С:Предприятие 8.3 часто возникает необходимость вынести тяжелые вычисления или запросы к внешним системам (например, получение данных с сайта) в фоновое задание. Это позволяет не блокировать интерфейс пользователя. Однако программисты часто сталкиваются с проблемой: в файловом варианте данные успешно возвращаются в форму, а в клиент-серверном — временное хранилище оказывается пустым. Рассмотрим подробно, почему это происходит и как правильно организовать передачу данных.

Разбор механизма работы временного хранилища

Для начала проанализируем ситуацию. Временное хранилище в 1С — это специфическая область памяти, время жизни которой ограничено. В клиент-серверном варианте фоновое задание выполняется в отдельном сеансе на сервере (процесс rphost). По умолчанию данные одного сеанса недоступны другому. Единственным исключением является механизм передачи данных через адрес, привязанный к Уникальному Идентификатору формы.

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

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

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

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

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


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

Реализация серверной части в фоновом задании

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


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

Получение результата и обработка ошибок

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


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

Альтернативный метод: Передача через сообщения фонового задания

В некоторых случаях использование временного хранилища может быть избыточным, особенно если нужно передать небольшую строку или сам новый адрес хранилища. Рассмотрим подробнее метод ФоновыеЗадания.ПолучитьСообщения().

Фоновое задание может использовать команду Сообщить(). Эти сообщения не выводятся пользователю напрямую, а накапливаются в объекте задания. Мы можем прочитать их из формы:

  1. В фоновом задании вызываем Сообщить(АдресНовогоХранилища).
  2. В обработчике ожидания вызываем Задание.ПолучитьСообщения().
  3. Извлекаем текст сообщения и используем его как адрес для ПолучитьИзВременногоХранилища.

Этот способ часто оказывается более надежным, если вы не хотите заранее создавать пустые адреса с привязкой к УникальныйИдентификатор. Однако помните, что для больших объемов данных (тяжелых таблиц) первый метод с предварительным резервированием адреса является стандартным и предпочтительным с точки зрения платформы 1С.

Важные советы для стабильной работы

Проанализируем еще несколько критических моментов:

1. Использование структур. Как отмечалось в обсуждении, лучше помещать в хранилище не «голую» таблицу значений, а структуру. Например: Новый Структура("Результат, Статус", ТаблицаДанных, Истина). Это помогает избежать проблем при десериализации данных между процессами сервера.

2. Время жизни хранилища. Если вы используете обычные формы, помните, что при закрытии формы или внезапном разрыве соединения временное хранилище, привязанное к UUID формы, будет очищено. Если фоновое задание выполняется очень долго (десятки минут), есть риск, что родительский сеанс «заснет» или закроется.

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

Таким образом, правильное использование УникальныйИдентификатор и понимание границ сеансов в 1С позволяют легко обходить ограничения клиент-серверной архитектуры и эффективно использовать фоновые вычисления.

← На главную