При выполнении обмена в распределенной информационной базе (РИБ) разработчики и администраторы нередко сталкиваются с ситуацией, когда после обновления конфигурации или при очередной загрузке данных система аварийно завершает чтение сообщения с системным исключением: «в этой транзакции уже происходили ошибки». Данная ошибка возникает на этапе выполнения метода ПланыОбмена.ПрочитатьИзменения() и блокирует штатный запуск периферийной информационной базы.
Проанализируем природу этой ошибки, разберем по шагам алгоритмы локализации сбойных данных и рассмотрим штатные способы восстановления работоспособности распределенной системы.
Важно понимать, что сообщение «в этой транзакции уже происходили ошибки» является вторичным. Платформа 1С:Предприятие генерирует его в том случае, когда внутри открытой транзакции уже произошло первичное исключение (которое могло быть неявно перехвачено блоком Попытка...Исключение), после чего была предпринята попытка выполнить любую другую операцию записи или фиксации транзакции. Платформа блокирует фиксацию такой транзакции ради сохранения целостности данных.
Выясним основные причины первичных ошибок при загрузке изменений:
ПередЗаписью, ПриЗаписи, ОбработкаПроверкиЗаполнения) отсутствует проверка режима загрузки, код начинает выполнять валидацию реквизитов, пересчет движений или контроль остатков, что в режиме обмена недопустимо.ЧтениеСообщенияОбмена, например, обращение к свойству ЧтениеСообщения.Отправитель происходит до корректного вызова метода ЧтениеСообщения.НачатьЧтение(ЧтениеXML), контекст чтения нарушается.Разберем, как точно определить, какой именно объект в файле обмена вызывает сбой транзакции. Для этого применим пошаговую диагностику.
ЧтениеXML = Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения);
ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
// Устанавливаем количество элементов в транзакции равным 1
КоличествоЭлементовВТранзакции = 1;
Попытка
ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения, КоличествоЭлементовВТранзакции);
Исключение
ЗаписьЖурналаРегистрации("ОбменДанными.ОшибкаЗагрузки",
УровеньЖурналаРегистрации.Ошибка,,,
ОписаниеОшибки());
КонецПопытки;
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
Установка размера транзакции в 1 позволяет изолировать каждый объект в индивидуальную транзакцию. В результате в Журнал регистрации запишется конкретный проблемный элемент данных, не прерывая чтение остальных корректных объектов.
Проанализируем прикладной код объектов, на которых произошел сбой. Распространенная ошибка разработчиков — выполнение логики интерактивного интерфейса или строгих бизнес-проверок при автоматической загрузке по РИБ.
В каждом обработчике событий ПередЗаписью и ПриЗаписи в модулях объектов и подписок на события обязательно должно присутствовать исключение логики при загрузке данных. Посмотрим на пример:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Обязательная проверка режима обмена данными
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Прикладные проверки и заполнение реквизитов
ПроверитьЗаполнениеРеквизитов(Отказ);
КонецПроцедуры
Флаг ОбменДанными.Загрузка = Истина устанавливается платформой автоматически в момент чтения изменений из сообщения РИБ. Если обработчик пытается выполнить расчет или отменить запись (Отказ = Истина) без проверки этого свойства, транзакция помечается ошибочной.
Если ошибка вызвана данными, зарегистрированными в узле центральной базы (например, битыми ссылками или некорректными наборами записей), применим метод локализации через выборочную регистрацию:
В ситуациях, когда требуется обновить структуру метаданных или скорректировать данные в периферийной базе автономно без применения промежуточных файлов обмена, выполним временное отключение узла от главного.
Разберем по шагам алгоритм автономного обслуживания периферийной базы:
// Отключение главного узла
ПланыОбмена.УстановитьГлавныйУзел(Неопределено);
.cf), выгруженного из центральной базы, через меню Конфигурация -> Загрузить конфигурацию из файла.F7).
// Восстановление связи с главным узлом
СсылкаГлавногоУзла = ПланыОбмена.НашПланОбменаРИБ.НайтиПоКоду("ЦБ");
Если ЗначениеЗаполнено(СсылкаГлавногоУзла) Тогда
ПланыОбмена.УстановитьГлавныйУзел(СсылкаГлавногоУзла);
КонецЕсли;
Данная последовательность действий позволяет синхронизировать метаданные узлов без передачи тяжелых пакетов изменений конфигурации через XML-сообщения обмена.