Почему в РИБ не загружаются движения документов, если ранее они были импортированы из XML-файла?

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

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

Рассмотрим сценарий: у нас есть Главный узел и подчиненный (кассовый) узел. Из-за блокировок СУБД во время пробития чеков ККМ было принято решение выгружать документы чеков из кассы в XML-файлы каждые 15 минут, а в Главном узле загружать их программно, очищая движения и снимая регистрацию изменений по документу. Ночью запускается стандартный РИБ. В результате мы сталкиваемся с проблемой: документы в Главном узле остаются проведенными, но их движения по регистрам полностью исчезают, хотя в дочернем узле все движения на месте. При этом, если документ перепровести в дочернем узле повторно, после следующего ночного обмена движения в Главном узле чудесным образом появляются. Давайте разберем по шагам, почему это происходит и как решить проблему.

В чем причина исчезновения движений? Анализируем механику РИБ

Для того чтобы понять суть проблемы, нам необходимо заглянуть под капот платформы 1С и вспомнить, как именно регистрируются изменения в планах обмена. Многие разработчики ошибочно полагают, что документ и его движения — это единое целое в контексте обмена данными. Это не так.

Документы и их движения (наборы записей регистров накопления, бухгалтерии, сведений и т.д.) регистрируются на узлах планов обмена независимо друг от друга. Данные о регистрации изменений хранятся в отдельных системных таблицах БД (таблицах изменений):

Когда вы в Главном узле принудительно очищаете движения импортированного из XML документа (например, через Движения.Записать()) или перепроводите его без формирования движений, платформа 1С автоматически фиксирует это действие. В таблицах изменений регистров для подчиненного узла регистрируется пустой набор записей.

Вызов метода ПланыОбмена.УдалитьРегистрациюИзменений(УзелСсылка, ДокОбъект) удаляет регистрацию изменений только для самого документа. Зарегистрированные пустые наборы записей по регистрам при этом остаются в базе Главного узла нетронутыми.

При запуске ночного обмена РИБ возникает классическая коллизия:

  1. Подчиненный узел пытается передать в Главный узел свои заполненные движения по документу.
  2. В Главном узле для подчиненного узла уже висит зарегистрированное изменение по тем же регистрам (но со знаком «пусто»).
  3. В РИБ действует жесткое платформенное правило разрешения конфликтов: «Главный узел всегда побеждает». Изменения, пришедшие из подчиненного узла, просто игнорируются. Платформа оставляет в Главном узле свой пустой набор записей.

Почему перепроведение документа в подчиненном узле решает проблему при повторном обмене? Потому что после первой ночной сессии обмена квитанция о приеме данных снимает «зависшую» регистрацию пустых движений в Главном узле. Коллизия исчезает. При повторном перепроведении в дочернем узле движения заново регистрируются и при следующем обмене успешно заходят в базу без конфликтов.

---

Решение 1: Точечное удаление регистрации изменений для движений

Самый правильный технический путь решения проблемы «в лоб» — при ручной очистке движений документа в Главном узле удалять регистрацию изменений не только самого документа, но и всех связанных с ним регистров. Для этого нам потребуется обходить коллекцию движений документа и передавать структуру отбора по регистратору в метод ПланыОбмена.УдалитьРегистрациюИзменений().

Рассмотрим пример кода, который необходимо выполнять в Главном узле после программного создания или изменения документа:


// Очищаем регистрацию изменений для самого документа
ПланыОбмена.УдалитьРегистрациюИзменений(УзелСсылка, ДокОбъект.Ссылка);

// Нам также нужно очистить регистрацию изменений по каждому регистру, где документ оставил след
Для Каждого НаборЗаписей Из ДокОбъект.Движения Цикл
    
    // Формируем структуру отбора по регистратору
    ОтборРегистратора = Новый Структура("Регистратор", ДокОбъект.Ссылка);
    
    // Удаляем регистрацию изменений набора записей для конкретного узла
    ПланыОбмена.УдалитьРегистрациюИзменений(УзелСсылка, НаборЗаписей.Метаданные(), ОтборРегистратора);
    
КонецЦикла;

Этот простой шаг предотвратит появление пустых зарегистрированных изменений в таблицах регистрации регистров Главного узла, и при ночном обмене РИБ движения из дочернего узла придут без коллизий.

---

Решение 2: Проверка признака «ОбменДанными.Загрузка»

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

Во время работы РИБ платформа устанавливает свойство ОбменДанными.Загрузка = Истина. Вся кастомная логика должна быть заблокирована при загрузке данных обмена:


Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    
    // Если происходит загрузка данных обмена, не вмешиваемся в движения!
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;
    
    // Ваш кастомный код очистки или модификации движений для ручного импорта
    ...
КонецПроцедуры

---

Альтернативные архитектурные решения проблемы блокировок

Если вы хотите уйти от сложного «костыльного» механизма параллельного обмена XML и ночного РИБ, рассмотрите более надежные архитектурные паттерны:

  1. Выделенный план обмена для оперативных данных. Вы можете создать отдельный, не связанный с РИБ план обмена. В его состав включите только те документы, которые нужны оперативно (например, Чеки ККМ), и настройте его запуск каждые 15 минут. По РИБ эти документы можно вообще исключить из обмена или обменивать раз в сутки. При этом объемы пересылаемых данных будут крайне малы, а блокировки базы снизятся до минимума.
  2. Интеграция через HTTP-сервисы. Настройте отправку чеков из кассового узла напрямую в Главный узел через HTTP POST-запросы сразу после пробития чека. Главный узел будет быстро принимать данные в формате JSON или XML и записывать их без проведения (или с проведением, если позволяет производительность), а ночной РИБ закроет все остальные потребности в синхронизации нормативно-справочной информации (НСИ).
  3. Оптимизация блокировок СУБД (устранение первопричины). Зачастую блокировки при пробитии чеков во время обмена возникают из-за автоматического режима управления блокировками в старых конфигурациях. Перевод базы данных на управляемый режим блокировок позволяет платформе блокировать таблицы СУБД точечно (на уровне конкретных строк регистра, а не таблиц целиком). Это полностью решает проблему конфликтов транзакций при обмене в фоновом режиме.

Используйте предложенные подходы, чтобы сделать ваши интеграционные механизмы в 1С стабильными и производительными!

← На главную