Как правильно передавать данные временного хранилища в фоновое задание через БСП?

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

При разработке конфигураций на платформе 1С:Предприятие с использованием Библиотеки Стандартных Подсистем (БСП) программисты часто сталкиваются с ситуацией, когда привычные методы платформы ведут себя иначе при использовании оберток БСП. Одним из таких камней преткновения является работа с фоновыми заданиями и временным хранилищем.

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

Суть проблемы: потеря контекста временного хранилища

Рассмотрим ситуацию. У нас есть форма (например, созданная через подключаемые команды БСП), в которой пользователь что-то делает. Мы помещаем некоторые данные во временное хранилище, привязанное к этой форме (используя УникальныйИдентификатор формы). Затем мы хотим запустить фоновое задание, которое эти данные обработает.

Если мы используем стандартный метод платформы:


// Прямой вызов платформы
ФоновыеЗадания.Выполнить("МойМодуль.МояПроцедура", Параметры, , "Наименование");

В этом случае, если четвертым параметром (Ключ) или неявно передать идентификатор формы, платформа может обеспечить "магию" связывания сеансов, и данные хранилища могут быть прочитаны (хотя это тоже имеет свои ограничения).

Однако, стандарты разработки 1С рекомендуют использовать подсистему Длительные операции из БСП. Код превращается в следующий:


// Вызов через БСП
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ДлительныеОперации.ВыполнитьВФоне("МойМодуль.МояПроцедура", ПараметрыПроцедуры, ПараметрыВыполнения);

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

Анализ причин: Сеансы и изоляция данных

Чтобы понять корень проблемы, обратимся к документации и сообщению №10 из обсуждения. Синтаксис-помощник гласит:

Временное хранилище, сформированное в одном сеансе, недоступно из другого сеанса.

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

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

Более того, разработчики БСП намеренно ограничивают такую практику. Рассмотрим почему.

Почему передавать адрес хранилища формы — плохая практика?

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

  1. Жизненный цикл формы: Временное хранилище формы живет ровно столько, сколько живет сама форма. Если пользователь нажмет кнопку "Запустить", а затем сразу закроет окно обработки, форма уничтожится. Вместе с ней очистится временное хранилище.
  2. Ошибка выполнения: Фоновое задание, которое в этот момент только начало работать и попыталось обратиться по адресу, получит ошибку или пустые данные. Это приведет к падению задания.

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

Решение 1: Передача данных через параметры (Рекомендуемое)

Как справедливо замечено в сообщении №8, самый надежный способ — не использовать передачу адреса. Вместо этого нужно получить данные на сервере в контексте вызова (перед запуском) и передать их как значение.

Алгоритм действий:

  1. На клиенте инициируем длительную операцию.
  2. Переходим на сервер в контекст формы.
  3. Извлекаем нужные данные из Временного хранилища (или из РеквизитаФормыВЗначение).
  4. Формируем структуру параметров.
  5. Запускаем фоновое задание, передавая данные, а не ссылку на них.

Пример кода:


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

// Процедура фонового задания (в общем модуле)
Процедура ОбработатьДанные(Параметры, АдресРезультата) Экспорт
    
    ТЗ = Параметры.ТаблицаДанных; // Работаем с копией данных, переданной в параметрах
    // ... логика обработки
    
КонецПроцедуры

Этот метод полностью исключает зависимость от жизни формы. Даже если пользователь закроет 1С, фоновое задание на сервере доработает с переданной копией данных.

Решение 2: Использование независимого временного хранилища

Иногда данных слишком много, чтобы передавать их через параметры (сериализация огромной Таблицы Значений в параметры может быть накладной). В этом случае можно использовать Временное Хранилище, но создать его нужно правильно.

Ошибка автора темы была в том, что хранилище было привязано к УникальныйИдентификатор формы. Чтобы данные были доступны в фоне и жили независимо от формы, нужно помещать их в хранилище с новым идентификатором.

Алгоритм действий:

  1. Генерируем новый УникальныйИдентификатор. Он не связан ни с одной формой.
  2. Помещаем данные в хранилище под этим идентификатором.
  3. Передаем адрес этого хранилища в фоновое задание.

Пример реализации:


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

КонецФункции

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

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

Решение 3: Тонкая настройка БСП (Для экспертов)

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

Если в структуру ПараметрыВыполнения (третий параметр функции ВыполнитьВФоне) добавить свойство, которое БСП передаст в ключ фонового задания, можно добиться поведения, аналогичного платформенному.

Однако, мы настоятельно рекомендуем не использовать этот подход для чтения данных формы, так как он возвращает нас к проблеме "Жизненный цикл формы" (см. выше). Разработчики БСП не зря усложнили этот путь — это защита от ошибок проектирования.

Резюме

  1. Проблема пустого хранилища в фоновом задании БСП связана с изоляцией сеансов и отсутствием автоматической привязки контекста формы в обертках БСП.
  2. Не пытайтесь передавать адрес временного хранилища, привязанного к форме (ЭтаФорма.УникальныйИдентификатор). Это ненадежно.
  3. Лучшее решение: Получите данные на сервере перед запуском и передайте их в параметры фонового задания как структуру или массив.
  4. Альтернативное решение (для больших данных): Поместите данные во временное хранилище с новым, ни к чему не привязанным уникальным идентификатором, и передайте этот адрес.
← На главную