При работе с обменами данными на базе технологии Конвертация данных 2.0 и механизмов Планов обмена разработчики часто сталкиваются со специфическим поведением системы. Ситуация выглядит следующим образом: в базе-приемнике (например, УПП2) в обработчике ПриЗагрузке срабатывает условие, по которому объект не должен быть записан (устанавливается Отмена = Истина). Объект действительно не сохраняется в базе-приемнике, однако при совершении обратного обмена база-источник (УПП1) считает, что данные успешно доставлены, и снимает этот объект с регистрации. В результате документ больше не выгружается, хотя фактически в приемнике его нет.
В этой статье мы подробно разберем, почему это происходит, проанализируем стандартные механизмы квитирования (подтверждения) сообщений в 1С и рассмотрим несколько способов решения задачи, чтобы объект был передан повторно.
Для начала проанализируем внутреннюю логику платформы 1С. Механизм планов обмена работает по принципу пакетов данных. Когда база-источник формирует сообщение обмена, она присваивает ему уникальный номер (например, 10) и запоминает, какие именно объекты (ссылки) вошли в этот пакет. Когда база-приемник загружает этот файл, она сохраняет у себя номер последнего принятого сообщения.
При ответном обмене база-приемник передает этот номер обратно источнику в качестве подтверждения. Как только УПП1 получает информацию, что сообщение №10 принято, она удаляет регистрацию для всех объектов, входивших в этот пакет. Системе «все равно», был ли конкретный документ записан внутри транзакции загрузки или нет — подтверждение работает для всего сообщения целиком.
Это самый надежный и «чистый» с точки зрения архитектуры способ. Вместо того чтобы пытаться вмешаться в стандартный процесс квитирования сообщений, мы реализуем логику запроса данных.
Разберем алгоритм по шагам:
УПП2), в обработчике ПриЗагрузке, если мы принимаем решение об отмене записи, мы должны где-то зафиксировать этот факт.УПП2 вспомогательный регистр сведений (например, ОбъектыДляПеререгистрации) и будем записывать туда ссылку или уникальный идентификатор объекта, который не был загружен.УПП2 в УПП1 настроим передачу данных из этого регистра.УПП1) при получении этих записей программно вызовем регистрацию изменений.Пример кода для регистрации объекта в источнике при получении «сигнала»:
ПланыОбмена.ЗарегистрироватьИзменения(УзелОбмена, СсылкаНаОбъект);
Этот метод позволяет системе штатно завершить цикл подтверждения получения данных, а затем сразу же поставить «проблемный» документ в очередь на следующую выгрузку. Для ручного контроля очереди обмена в базах на обычном приложении (таких как УПП в примере) пригодится обработка для регистрации изменений для обмена.
В обсуждении на форуме предлагался вариант со сбросом номера сообщения. Рассмотрим, как это реализовать технически, и разберем риски. В правилах обмена (в обработчиках) можно получить доступ к узлу обмена и программно изменить НомерПринятого.
Пример кода для изменения номеров сообщений (использовать с осторожностью):
ОбъектУзла = УзелОбмена.ПолучитьОбъект();
Попытка
// Устанавливаем номер так, чтобы источник считал пакет не доставленным
ОбъектУзла.НомерОтправленного = НомерОтправленного;
ОбъектУзла.НомерПринятого = НомерПринятого;
ОбъектУзла.Записать();
Исключение
Сообщить("Ошибка при изменении номеров сообщений: " + ОписаниеОшибки());
КонецПопытки;
Внимание: проанализируем опасность этого метода! Если в сообщении №10 передавалось 100 документов, и вы отменили загрузку только одного, а затем сбросили номер сообщения, то при следующем сеансе обмена источник повторно пришлет все 100 документов. Это создает колоссальную нагрузку на систему и может привести к зацикливанию обмена, если ошибка загрузки одного объекта будет постоянной.
Вместо использования Отмена = Истина, мы можем проанализировать ситуацию иначе. Рассмотрим вариант записи документа «как есть», но с определенным признаком. Например, мы можем создать в документе дополнительный реквизит СостояниеЗагрузки (перечисление: Успешно, ТребуетДоработки) или записывать документ непроведенным.
Плюсы этого подхода:
УПП2 видит проблемный документ, исправляет данные и проводит его вручную.Если нам критично, чтобы ни один объект из пакета не считался принятым, если хотя бы один из них не загрузился, можно использовать вызов исключения. В 1С загрузка сообщения обычно происходит в рамках одной транзакции.
Если внутри обработчика ПриЗагрузке вызвать ВызватьИсключение "Текст ошибки", то транзакция записи будет прервана. При этом база-приемник не обновит номер принятого сообщения. При следующем обмене УПП1 снова отправит тот же самый файл. Однако помните, что это остановит загрузку всех объектов из текущего сообщения.
Проанализировав все способы, мы рекомендуем придерживаться следующей логики:
Объекты обмена с ошибками. В БСП механизмы повторной регистрации зачастую уже реализованы «из коробки» и позволяют регистрировать ошибки загрузки без написания сложного кода.НомерПринятого и НомерОтправленного в коде правил обмена, так как это часто ведет к рассинхронизации баз и «застреванию» обмена.Таким образом, самым профессиональным подходом будет позволить системе снять регистрацию, но сразу же программно создать новую заявку на выгрузку этого объекта через обратный сигнал из приемника в источник. Если же автоматический механизм пока не настроен, для быстрого исправления ситуации подойдет инструмент для ручной регистрации объектов в плане обмена прямо из формы.