Как исправить ошибку «В данной транзакции происходили ошибки» при работе с сервисами интеграции в 1С?

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

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

Выясняем причину: механизм «заражения» транзакции

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

  1. Программа начинает выполнение кода.
  2. Вызывается метод Записать(РежимЗаписиДокумента.Проведение).
  3. Если внутри проведения (в модуле документа, в подписках на события или при записи в регистры) возникает любая ошибка СУБД (например, нарушение уникальности, проверка остатков, ошибка в SQL-запросе), транзакция помечается платформой как «битая» (состояние Rollback Only).
  4. Несмотря на то, что код обернут в Попытка...Исключение, состояние транзакции уже невозможно изменить. Платформа 1С «запоминает», что внутри этой транзакционной единицы произошел сбой, и блокирует любые дальнейшие операции записи в базу данных.

Проанализируем фрагмент кода, который вызывает проблему:


Исключение
    ТекстОшибки = ТекстОшибки + "Не удалось провести документ: "+ ОбъектИБ;
    ОбъектИБ.ОбменДанными.Загрузка = Истина;
    ОбъектИБ.Записать(); // Здесь возникнет ошибка «В данной транзакции происходили ошибки»
КонецПопытки;

Как мы видим, в блоке Исключение автор пытается «спасти» объект и просто записать его без проведения. Однако, поскольку транзакция уже помечена ошибочной, любая последующая команда Записать() вызовет отказ системы. Платформа просто не позволит зафиксировать частичные изменения, если где-то ранее в этой же транзакции произошел сбой.

Разберем вложенность транзакций в 1С

Важно помнить, что 1С:Предприятие не поддерживает полноценные вложенные транзакции на уровне СУБД. Когда мы вызываем НачатьТранзакцию() внутри уже активной транзакции, платформа просто увеличивает счетчик вложенности. Рассмотрим основные правила:

Решение №1: Ручное управление транзакциями

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

  1. Снимем флаг «В транзакции» в настройках сервиса интеграции.
  2. В коде обработки сообщения будем использовать явные вызовы управления транзакциями.

Посмотрим на пример правильной реализации:


Процедура ОбработатьСообщение(ДанныеСообщения)
    
    // 1. Сначала подготавливаем данные без открытия транзакции
    ДокументОбъект = СоздатьДокументНаОснованииДанных(ДанныеСообщения);
    
    // 2. Открываем транзакцию только для критического участка
    НачатьТранзакцию();
    Попытка
        // Попытка проведения
        ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение);
        ЗафиксироватьТранзакцию();
    Исключение
        // 3. Если произошла ошибка, СНАЧАЛА откатываем сломанную транзакцию
        ОтменитьТранзакцию();
        
        // 4. Теперь, когда мы вне транзакции, мы можем выполнить другие действия
        ЗаписатьЛогОшибки(ОписаниеОшибки(), ДанныеСообщения.Идентификатор);
        
        // Попробуем просто записать документ в режиме обмена вне основной транзакции
        ДокументОбъект.ОбменДанными.Загрузка = Истина;
        ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
    КонецПопытки;
    
КонецПроцедуры

В данном примере мы разделяем попытку проведения и запись лога. После вызова ОтменитьТранзакцию() контекст базы данных очищается, и мы можем начать новую транзакцию или выполнить простую запись.

Решение №2: Использование фоновых заданий для логирования

Если специфика сервиса требует, чтобы основная транзакция оставалась активной (например, это контролирует сама шина данных), но нам крайне важно записать ошибку в информационную базу именно в момент сбоя, мы можем использовать фоновые задания.

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


// В блоке Исключение основной процедуры
ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(ТекстОшибки);
ПараметрыЗадания.Добавить(ИдентификаторСообщения);

ФоновыеЗадания.Выполнить("ОбщийМодульИнтеграция.ЗаписатьОшибкуВЛог", ПараметрыЗадания);

Метод ЗаписатьОшибкуВЛог создаст новую запись в справочнике или регистре сведений, и этот процесс никак не будет зависеть от того, откатится ли основная транзакция сервиса интеграции.

Решение №3: Предварительная проверка данных

Часто ошибка «В данной транзакции происходили ошибки» возникает из-за того, что мы пытаемся провести документ, который заведомо содержит некорректные данные. Рассмотрим стратегию «мягкой» проверки:

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

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

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

← На главную