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