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

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

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

Правила работы временного хранилища при взаимодействии с фоновыми заданиями

В платформе 1С:Предприятие временное хранилище изолировано в рамках конкретного сеанса. Данные, сформированные в одном сеансе, недоступны для других сеансов. Исключением является обмен данными между фоновым заданием и сеансом, который инициировал его запуск.

Для корректной передачи данных необходимо соблюдать строгую последовательность действий:

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

Реализация механизма запуска и получения результата

Рассмотрим программный пример запуска фонового задания из формы и последующего считывания результата через обработчик ожидания.

В модуле формы подготавливаем адрес временного хранилища и запускаем фоновый процесс:


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

В серверном общем модуле описываем процедуру фонового задания. Результат помещается по переданному адресу:


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

На клиенте периодически опрашиваем состояние задания. Считывание данных выполняем только после того, как статус фонового задания изменится на Завершено:


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

&НаСервереБезКонтекста
Функция ПроверитьЗаданиеНаСервере(ИдентификаторЗадания, АдресВХранилище)
    
    Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдентификаторЗадания);
    
    Если Задание <> Неопределено И Задание.Состояние = СостояниеФоновогоЗадания.Завершено Тогда
        Возврат ПолучитьИзВременногоХранилища(АдресВХранилище);
    КонецЕсли;
    
    Возврат Неопределено;
    
КонецФункции

Почему временное хранилище может возвращать Неопределено

Проанализируем технические причины, по которым временное хранилище перестает отдавать данные, особенно если сбой проявляется не сразу, а спустя несколько дней непрерывной работы базы:

  1. Не привязан идентификатор формы: Если вызвать ПоместитьВоВременноеХранилище(Неопределено) без второго параметра УникальныйИдентификатор, платформа связывает адрес с текущим вызовом сервера. При завершении вызова данные удаляются сборщиком мусора.
  2. Попытка прочитать данные до завершения задания: Если фоновое задание еще выполняется (состояние Активно), родительский сеанс вернет Неопределено при вызове ПолучитьИзВременногоХранилища().
  3. Многопроцессный кластер серверов 1С: Временное хранилище управляется сервисом сеансовых данных. Если родительский сеанс и фоновое задание распределены по разным процессам rphost, при высокой нагрузке или утечках памяти в процессах кластера синхронизация между процессами может давать сбои.
  4. Блокировка каталога сеансовых данных snccntx: Физически временные объекты кэшируются на диске сервера. Антивирусная проверка папки srvinfo или нехватка дискового пространства приводят к потере сеансовых данных.
  5. Специфика обычных форм (в толстом клиенте / УПП 1.3): В обычном приложении время жизни временного хранилища без четкой привязки к контексту управляемой формы может преждевременно завершаться серверным сборщиком мусора.

Настройка сервера и альтернативные способы передачи данных

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

  1. Настройка кластера: В консоли администрирования 1С настроим интервал перезапуска рабочих процессов rphost (например, раз в сутки в нерабочее время) и добавим каталоги кластера (включая папку snccntx) в исключения антивируса.
  2. Использование Хранилища Общих Настроек: Для гарантированной передачи данных без привязки к оперативной памяти процессов rphost сохраняем результат в системную таблицу базы через ХранилищеОбщихНастроек.Сохранить() по уникальному ключу фонового задания, а после чтения удаляем его методом ХранилищеОбщихНастроек.Удалить().
  3. Служебный регистр сведений: Создаем непериодический регистр сведений с измерением ИдентификаторЗадания (тип УникальныйИдентификатор) и ресурсом Данные (тип ХранилищеЗначения). Этот способ обеспечивает максимальную надежность транзакционной записи и чтения больших объемов данных.
  4. Подсистема «Длительные операции» БСП: Переход на стандартные методы Библиотеки Стандартных Подсистем (ДлительныеОперации.ЗапуститьВыполнениеВФоне) позволяет автоматически обрабатывать отказоустойчивость, прогресс выполнения и очистку временных ресурсов.
← На главную