Почему возникает ошибка «SDBL: Открытых транзакций нет» в подписках на события и как правильно организовать выгрузку данных?

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

В практике разработки на платформе 1С:Предприятие 8.3 часто возникает задача оперативной передачи данных между системами. Одним из первых приходящих на ум решений является использование механизма подписок на события. Однако неправильное использование этого инструмента может привести к трудноуловимым ошибкам, таким как «Ошибка SDBL: Открытых транзакций нет». Рассмотрим подробнее, почему это происходит, проанализируем типичные ошибки в коде и определим наиболее эффективные стратегии интеграции.

Разберем причину ошибки SDBL

Ошибка SDBL: Открытых транзакций нет при выполнении запроса к ресурсу /e1cib/logForm (или любому другому) обычно сигнализирует о том, что транзакция, в рамках которой выполнялось действие, была аварийно завершена или «разрушена» на уровне сервера баз данных, хотя код приложения все еще пытается к ней обратиться. Выясним причину этого явления в контексте подписок на события.

Когда мы создаем подписку на событие ПриЗаписи, наш код выполняется внутри неявной транзакции записи объекта. Платформа ожидает, что все действия внутри этой транзакции будут быстрыми и надежными. Если внутри подписки вызывается сложный механизм, такой как обработка УниверсальныйОбменДаннымиXML, происходит следующее:

  1. Вложенные транзакции: Обработка обмена может инициировать собственные транзакции или работу с временными таблицами. Если во внутреннем механизме происходит сбой, он может попытаться отменить свою транзакцию, что в ряде случаев «ломает» общую транзакцию записи объекта 1С.
  2. Таймауты и блокировки: Длительные операции ввода-вывода (запись файла на диск, ожидание ответа от сетевого ресурса) блокируют таблицу справочника. Если время ожидания превышает установленные лимиты SDBL, соединение разрывается.
  3. Крах контекста при работе с классификаторами: При добавлении данных из классификаторов (например, СтраныМира или АдресныеСведения), БСП запускает сложные фоновые процессы. Наложение вашей подписки на этот процесс создает конфликт блокировок, который система интерпретирует как потерю транзакционного контекста.

Проанализируем пример некорректного кода

Рассмотрим код, который часто становится причиной проблем. В данном примере разработчик пытается выполнить полную инициализацию правил обмена при каждой записи элемента:


Процедура ВыгрузкаВЕрпСтраныМира() Экспорт 
    Узел = ПланыОбмена.ВыгрузкаВЕрпСтраныМира.НайтиПоКоду("ЕРП");
    Выборка = ПланыОбмена.ВыбратьИзменения(Узел, Узел.НомерОтправленного); 
    
    Если Выборка.Следующий() Тогда
        // ... формирование пути к файлу ...
        Обработка = Обработки.УниверсальныйОбменДаннымиXML.Создать();
        Обработка.РежимОбмена = "Выгрузка";    
        Обработка.ИмяФайлаПравилОбмена  = ПутьНаДиске + "ПравилаОбмена.xml";
        
        // КРИТИЧЕСКАЯ ОШИБКА: Парсинг XML правил внутри транзакции записи
        Обработка.ЗагрузитьПравилаОбмена();
        
        // ... настройка правил выгрузки ...
        Обработка.ВыполнитьВыгрузку(); 
    КонецЕсли;
КонецПроцедуры

Почему такой подход считается «антипаттерном»? Выясним основные причины:

Вариант 1: Использование регламентных заданий (Рекомендуется)

Это самый надежный и «каноничный» способ. Мы разделяем процесс записи данных и процесс их передачи. Посмотрим на алгоритм действий:

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

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

Вариант 2: Использование фоновых заданий для «мгновенного» обмена

Если бизнес-требования диктуют необходимость передать данные буквально в ту же секунду, используем асинхронный вызов через ФоновыеЗадания. Рассмотрим пример реализации в подписке на событие:


// Процедура-обработчик подписки на событие ПриЗаписи
Процедура ПриЗаписиСтраныМираПодписка(Источник, Отказ) Экспорт
    Если Отказ Тогда Возврат; КонецЕсли;
    
    // Вместо выполнения обмена здесь, запускаем фоновый поток
    ПараметрыЗадания = Новый Массив;
    ПараметрыЗадания.Добавить(Источник.Ссылка);
    
    ФоновыеЗадания.Выполнить("МойОбщийМодуль.ВыполнитьВыгрузкуОбъектаФоново", ПараметрыЗадания);
КонецПроцедуры

В чем преимущество? Рассмотрим ситуацию: пользователь нажимает «Записать», транзакция в базе данных завершается за миллисекунды, управление возвращается в интерфейс. В это время на сервере создается отдельный поток, который спокойно (вне транзакции пользователя) подготавливает XML и отправляет его в ЕРП. Если в фоновом задании произойдет ошибка (например, занят файл), это никак не помешает пользователю работать дальше.

Вариант 3: Оптимизация работы с «Универсальным обменом»

Если вы все же решили вызывать выгрузку программно (но желательно в фоновом режиме), проанализируем, как ускорить этот процесс. Главная «точка торможения» — это правила обмена. Посмотрим, как можно избежать постоянной загрузки правил:

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

Подведем итоги

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

Соблюдение этих архитектурных принципов не только избавит вас от ошибок транзакций, но и сделает систему масштабируемой и устойчивой к высоким нагрузкам.

← На главную