В процессе поддержки интеграций между базами 1С программисты часто сталкиваются с загадочным поведением планов обмена: некоторые документы упорно не переносятся в базу-приемник. При этом ручная регистрация объекта через стандартные обработки решает проблему — документ перегружается без нареканий. Но при штатном автоматическом обмене объект просто «исчезает» из регистрации в источнике, так и не появившись в приемнике.
В этой статье мы подробно разберем физику этого процесса, выясним, почему документы «выпадают» из обмена, и реализуем надежную систему логирования и трассировки изменений, которая поможет раз и навсегда определить виновную сторону без изнурительной отладки «в лоб» на «живой» базе.
Для начала давайте разберем, как платформа 1С работает с таблицами регистрации изменений на уровне СУБД. Это критически важно для понимания сути проблемы.
Документ.РеализацияТоваровУслуг.Изменения) создается запись. В этой записи поле НомерСообщения по умолчанию имеет значение NULL.ВыбратьИзменения(). Платформа временно присваивает всем выбранным записям номер отправляемого сообщения (например, 45).УдалитьРегистрациюИзменений(), который физически удаляет из таблицы изменений все записи, у которых НомерСообщения меньше или равен 45.Где же кроется баг?
Проблема возникает в момент формирования файла выгрузки. Сценарий выглядит следующим образом:
Документ успешно зарегистрировался в плане обмена (НомерСообщения = NULL). При начале обмена ему присвоился номер сообщения 45. Однако в процессе выгрузки сработали правила регистрации объектов (ПРО) или фильтры в правилах конвертации (ПКО/ПВД). Например, в правилах прописано условие: «Не выгружать документы по закрытым организациям» или «Игнорировать документы с пустой номенклатурой».
В результате:
45.45 и благополучно удаляет регистрацию изменений для нашего документа.В итоге регистрация стерта, документ не перенесен, а вы пребываете в недоумении. Именно поэтому повторное перепроведение документа (когда номер сообщения снова сбрасывается в NULL) временно решает проблему.
---
Чтобы быстро поймать документ «за руку» прямо во время обмена, мы можем использовать прямые запросы к таблицам регистрации изменений. По умолчанию конструктор запросов не показывает эти таблицы, но к ним можно обратиться программно.
Давайте напишем небольшой запрос, который покажет состояние регистрации для конкретного типа документов:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияИзменения.Ссылка КАК Документ,
| РеализацияИзменения.Узел КАК УзелОбмена,
| РеализацияИзменения.НомерСообщения КАК НомерСообщения
|ИЗ
| Документ.РеализацияТоваровУслуг.Изменения КАК РеализацияИзменения
|ГДЕ
| РеализацияИзменения.Ссылка = &ПроблемныйДокумент";
Запрос.УстановитьПараметр("ПроблемныйДокумент", ПроблемныйДокументСсылка);
РезультатЗапроса = Запрос.Выполнить();
Если НЕ РезультатЗапроса.Пустой() Тогда
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
Если Выборка.НомерСообщения = Неопределено Тогда
Сообщить("Документ зарегистрирован, но еще не включался в пакеты обмена (НомерСообщения = NULL)");
Иначе
Сообщить("Документ подготовлен к отправке в пакете № " + Выборка.НомерСообщения);
КонецЕсли;
КонецЦикла;
Иначе
Сообщить("Регистрация изменений для данного документа отсутствует.");
КонецЕсли;
Если перед запуском обмена вы видите, что у документа заполнен НомерСообщения, а после завершения обмена запись исчезает, но документ так и не появился в приемнике — значит, проблема на стороне источника (документ отсекается правилами выгрузки).
---
Для постоянного мониторинга обмена на «живой» базе (где нельзя останавливать процессы ради отладки) лучшим решением будет логирование шагов обмена в Журнал регистрации. Чтобы не изменять типовую конфигурацию, мы реализуем это через механизм расширений конфигурации.
Нам понадобятся точки перехвата в двух базах.
Мы должны зафиксировать момент, когда платформа реально записывает данные объекта в XML-файл обмена. В типовых конфигурациях на базе БСП (Библиотека Стандартных Подсистем) за это отвечает общий модуль ОбменДаннымиСервер.
Создадим расширение и перехватим процедуру выгрузки объектов методом &После или &Перед:
&После("ВыгрузитьОбъектДанных")
Процедура Лог_ВыгрузитьОбъектДанных(ДанныеПриемника, ДанныеИсточника, СопутствующиеДанные, КомпонентОбмена)
СсылкаНаОбъект = ДанныеИсточника.Ссылка;
ТипОбъекта = СсылкаНаОбъект.Метаданные().Имя;
// Фильтруем только интересующие нас типы документов для экономии места в журнале
Если ТипОбъекта = "РеализацияТоваровУслуг" Тогда
ИмяСобытияЛога = "ОбменДанными.ВыгрузкаОбъекта";
ТекстКомментария = СтрШаблон(
"Объект успешно записан в файл обмена. Узел: %1. Ссылка: %2, Номер: %3",
Строка(КомпонентОбмена.УзелОбмена),
Строка(СсылкаНаОбъект),
СсылкаНаОбъект.Номер
);
ЗаписьЖурналаРегистрации(
ИмяСобытияЛога,
УровеньЖурналаРегистрации.Информация,
СсылкаНаОбъект.Метаданные(),
СсылкаНаОбъект,
ТекстКомментария
);
КонецЕсли;
КонецПроцедуры
Теперь необходимо убедиться, что документ дошел до приемника и попытался записаться. Перехватим аналогичную процедуру загрузки в базе-приемнике:
&После("ЗаписатьПолученныеДанные")
Процедура Лог_ЗаписатьПолученныеДанные(ПолученныеДанные, КомпонентОбмена)
СсылкаНаОбъект = ПолученныеДанные.Ссылка;
ТипОбъекта = СсылкаНаОбъект.Метаданные().Имя;
Если ТипОбъекта = "РеализацияТоваровУслуг" Тогда
ИмяСобытияЛога = "ОбменДанными.ЗагрузкаОбъекта";
ТекстКомментария = СтрШаблон(
"Объект успешно получен и записан в базу-приемник. Узел: %1. Ссылка: %2, Номер: %3",
Строка(КомпонентОбмена.УзелОбмена),
Строка(СсылкаНаОбъект),
СсылкаНаОбъект.Номер
);
ЗаписьЖурналаРегистрации(
ИмяСобытияЛога,
УровеньЖурналаРегистрации.Информация,
СсылкаНаОбъект.Метаданные(),
СсылкаНаОбъект,
ТекстКомментария
);
КонецЕсли;
КонецПроцедуры
Если при анализе логов после очередного сбоя вы обнаружите запись «ВыгрузкаОбъекта» в источнике, но в приемнике запись «ЗагрузкаОбъекта» отсутствует — значит, произошел сбой при чтении пакета или объект был отвергнут транзакцией записи в приемнике (в таком случае в журнале регистрации приемника рядом обязательно будет запись об ошибке выполнения транзакции).
---
Если ваши конфигурации построены на современных версиях БСП, вам не обязательно сразу писать код. Разработчики БСП уже заложили мощный функционал для трассировки.
Выполним следующие шаги для включения диагностики:
_БСП.ОбменДанными, где будет четко написано, почему тот или иной объект был пропущен при выгрузке.Используя предложенные методы контроля таблиц изменений и логирования событий обмена, мы переводим процесс поиска ошибок из плоскости «угадывания» в плоскость точного инженерного анализа.