В процессе разработки на платформе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда при переходе выполнения кода в фоновое задание (ФЗ) «исчезают» привычные данные: параметры сеанса, значения в глобальных переменных или содержимое программного стека. Рассмотрим подробнее, почему это происходит и как правильно организовать передачу контекста между основным сеансом и фоновым процессом.
Для начала проанализируем архитектуру платформы. В 1С каждое фоновое задание — это полностью обособленный сеанс. Когда мы вызываем метод для запуска фонового задания, сервер 1С создает новый поток в рабочем процессе rphost. Этот поток инициализирует новое окружение, которое не имеет прямой связи с памятью того сеанса, который инициировал запуск.
Основные причины потери данных:
ПараметрыСеанса), инициализированные в клиентском сеансе, в фоновом задании будут иметь значения по умолчанию или будут не инициализированы.Выясним причину, почему разработчики иногда пытаются найти «родительское задание». Это часто связано с желанием реализовать аспектно-ориентированное программирование (АОП) или сквозное логирование, где нужно понимать всю цепочку вызовов. Однако в 1С такая связь не поддерживается платформой «из коробки» автоматически.
Самый правильный и надежный способ передать уникальные для пользователя значения — использовать аргументы метода Выполнить менеджера фоновых заданий. Проанализируем ситуацию: если нам нужно передать настройки пользователя или идентификатор текущей операции, мы должны упаковать их в структуру.
Рассмотрим пример кода для запуска фонового задания с передачей параметров:
// В родительском сеансе (например, в модуле формы или команды)
ПараметрыЗапуска = Новый Структура;
ПараметрыЗапуска.Вставить("ТекущийПользователь", ПараметрыСеанса.ТекущийПользователь);
ПараметрыЗапуска.Вставить("Подразделение", ПараметрыСеанса.ТекущееПодразделение);
ПараметрыЗапуска.Вставить("ДополнительныйКонтекст", "ЗначениеУникальноеДляСеанса");
МассивПараметров = Новый Массив;
МассивПараметров.Добавить(ПараметрыЗапуска);
ФоновыеЗадания.Выполнить("МойОбщийМодуль.ВыполнитьДлительнуюОперацию", МассивПараметров, "УникальныйКлючЗадания", "Наименование задания");
В процедуре, которую вызывает фоновое задание, мы принимаем эту структуру и используем ее для инициализации локальной логики:
// В общем модуле (МойОбщийМодуль)
Процедура ВыполнитьДлительнуюОперацию(ПараметрыКонтекста) Экспорт
// Здесь мы можем использовать переданные данные
Пользователь = ПараметрыКонтекста.ТекущийПользователь;
// ВНИМАНИЕ: Параметры сеанса текущего (фонового) сеанса все еще пусты!
// Если код внутри этой процедуры обращается к ПараметрыСеанса напрямую,
// вам нужно будет их проинициализировать вручную на основе ПараметрыКонтекста.
КонецПроцедуры
Если ваша конфигурация построена на базе БСП, разберем, как этот вопрос решен на уровне стандарта. Подсистема «Длительные операции» берет на себя часть работы по «пробросу» контекста.
При использовании метода ДлительныеОперации.ВыполнитьВФоне, платформа автоматически пытается сохранить часть клиентского контекста (например, параметры разделения данных или настройки часового пояса). БСП использует структуру ПараметрыКлиентаНаСервере, которая передается внутрь ФЗ.
Посмотрим на пример работы через БСП:
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = "Обработка данных пользователя";
// Можно добавить свои данные в структуру параметров
ДопИнформация = Новый Структура("МойКлюч", "МоеЗначение");
Результат = ДлительныеОперации.ВыполнитьВФоне("МойОбщийМодуль.ПроцедураБСП", ДопИнформация, ПараметрыВыполнения);
Часто возникает вопрос: можно ли передать адрес временного хранилища в фоновое задание? Здесь есть критически важный нюанс. По умолчанию временное хранилище привязано к сеансу.
Если вы просто передадите строку-адрес, полученную методом ПоместитьВоВременноеХранилище(Данные, УникальныйИдентификаторФормы), фоновое задание не сможет прочитать эти данные, так как оно работает в другом сеансе. Чтобы данные стали доступны в ФЗ, необходимо использовать специальный идентификатор:
УникальныйИдентификатор).Однако помните, что наиболее надежным способом передачи больших объемов данных между сеансами является использование промежуточных таблиц (регистров сведений) или принудительное копирование данных в область, доступную всем сеансам (хотя это менее безопасно с точки зрения очистки памяти).
Проанализируем ситуацию, когда нам нужно в коде ФЗ понять, «кто я». У объекта ФоновоеЗадание есть свойства Ключ и Наименование. При запуске вы можете поместить в Ключ некий токен (например, UUID родительского процесса).
Внутри фонового задания получить эти данные можно так:
ТекущееФЗ = ФоновыеЗадания.ПолучитьТекущееФоновоеЗадание();
ИдентификаторРодителя = ТекущееФЗ.Ключ;
// Теперь мы знаем, в рамках какой бизнес-логики мы запущены
Подведем итог. Чтобы избежать проблем с «разрывом контекста», придерживайтесь следующих правил:
ПараметрыСеанса пусты или содержат значения по умолчанию.ИнициализироватьКонтекстФоновогоЗадания(СтруктураПараметров), которая будет заполнять параметры сеанса ФЗ значениями из переданной структуры в самом начале работы задания.УстановкаПараметровСеанса в модуле сеанса. Вы можете использовать его для базовой настройки окружения фонового процесса.Таким образом, «проблема 1С» с потерей контекста — это не ошибка, а архитектурное решение, направленное на масштабируемость и изоляцию процессов. Грамотное использование структур параметров при вызове ФоновыеЗадания.Выполнить позволяет полностью решить задачу передачи любых пользовательских данных вниз по стеку выполнения.