Почему фоновое задание не находит объект, созданный в основной транзакции?

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

При разработке интеграционных решений в 1С часто возникает соблазн запустить фоновое задание непосредственно в подписке на событие ПриЗаписи или ПослеЗаписи. Однако такой подход приводит к ошибке Объект не найден. Давайте разберемся, почему это происходит и как выстроить архитектуру системы правильно.

Суть проблемы: изоляция транзакций

Когда мы записываем элемент справочника, платформа открывает транзакцию СУБД. Пока эта транзакция не завершена (COMMIT не выполнен), данные объекта физически еще не записаны в базу данных — они находятся в «подвешенном» состоянии для других сеансов. В тот момент, когда мы из подписки запускаем фоновое задание, оно стартует в отдельном сеансе. Согласно уровням изоляции транзакций в базе данных, этот второй сеанс просто «не видит» еще не зафиксированных изменений в первом сеансе. Ссылка на объект существует в памяти, но обратиться к ней через запрос или метод ПолучитьОбъект() не удается, так как в базе данных этот объект еще «не родился».

Как решить проблему «Объекта не найден»

Существует несколько подходов к решению этой задачи, от простых «заплаток» до архитектурно верных решений.

Вариант 1: Использование регистра сведений как очереди

Это один из самых надежных методов. Вместо того чтобы сразу запускать «тяжелый» процесс, мы фиксируем факт необходимости отправки данных в специальном РегистрСведений. Этот регистр хранит ссылку на объект и статус обработки.

  1. Создаем РегистрСведений, например, с названием ОчередьОбменов.
  2. В подписке на событие ПослеЗаписи создаем запись в этот регистр.
  3. Настраиваем РегламентноеЗадание, которое работает по расписанию и считывает данные из регистра.

Поскольку запись в регистр происходит в рамках той же транзакции, что и запись справочника, проблема «не найденного объекта» исключается полностью. Регламентное задание берет данные, которые уже гарантированно записаны в базу.


// Пример записи в очередь в подписке на событие
НаборЗаписей = РегистрыСведений.ОчередьОбменов.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Объект.Установить(Источник.Ссылка);
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Объект = Источник.Ссылка;
НоваяЗапись.Статус = Перечисления.СтатусыОчереди.КОбработке;
НаборЗаписей.Записать();

Вариант 2: Использование механизмов плана обмена

Если ваша задача — интеграция, то ПланОбмена является штатным и наиболее подходящим инструментом. Механизм регистрации изменений в ПланОбмена работает на уровне платформы.

Этот метод исключает риск «запуска ста тысяч фоновых заданий» при групповой обработке, так как очередь накапливается в системных таблицах и обрабатывается пакетно.

Почему не стоит запускать фоновое задание напрямую

Рассмотрим риски такого подхода подробно:

  1. Исчерпание ресурсов: Каждое фоновое задание — это отдельный процесс rphost. При групповой перезаписи справочника из 10 000 элементов система попытается запустить 10 000 фоновых заданий, что приведет к падению сервера приложений.
  2. Непредсказуемость: Зависимость от времени завершения транзакции делает код нестабильным. Если транзакция затянется (например, из-за блокировок), фоновое задание свалится с ошибкой.
  3. Сложность отладки: Ошибки, возникающие в фоновых процессах, сложнее локализовать и воспроизвести в среде разработчика.

Итог: рекомендуемая архитектура

Для создания масштабируемой системы обмена данными необходимо придерживаться принципа асинхронной обработки:

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

← На главную