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

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

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

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

Почему регистрация изменений не очищается автоматически

Проанализируем архитектуру планов обмена. В распределенных информационных базах (РИБ) многие низкоуровневые операции скрыты платформой, однако в произвольных (не-РИБ) планах обмена платформа никогда не удаляет регистрацию неявно. Вызов метода ЧтениеСообщения.ЗакончитьЧтение() выполняет только служебные действия: фиксирует факт прочтения файла и обновляет реквизит узла НомерПринятого. Сама очистка записей в таблице изменений всегда должна быть явно вызвана в коде разработчиком.

Механизм подтверждения доставки строится на номерах сообщений:

  1. База А формирует исходящее сообщение с определенным номером (например, №5) и фиксирует этот номер для всех выгруженных объектов в таблице изменений.
  2. База Б принимает сообщение №5, запоминает его и при своей следующей выгрузке записывает в заголовок пакета подтверждение: «Я приняла сообщение №5».
  3. База А при чтении входящего пакета от Базы Б считывает номер принятого ею сообщения и удаляет у себя регистрацию всех тех изменений, чей номер не превышает подтвержденный.

Программная очистка регистрации изменений по квитанции

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

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


ЧтениеXML = Новый ЧтениеXML();
ЧтениеXML.ОткрытьФайл(ИмяФайлаЗагрузки);

ЧтениеСообщения = ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);

НачатьТранзакцию();
Попытка
    // Считываем полезную нагрузку
    Пока ВозможностьЧтенияXML(ЧтениеXML) Цикл
        Данные = ПрочитатьXML(ЧтениеXML);
        
        // Устанавливаем признак обмена данными для отключения прикладных проверок
        Данные.ОбменДанными.Загрузка = Истина;
        Данные.Записать();
    КонецЦикла;

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

    ЧтениеСообщения.ЗакончитьЧтение();
    ЧтениеXML.Закрыть();

    ЗафиксироватьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    ЧтениеСообщения.ЗакончитьЧтение();
    ЧтениеXML.Закрыть();
    ВызватьИсключение;
КонецПопытки;

Разберем параметры вызова метода ПланыОбмена.УдалитьРегистрациюИзменений(Узел, НомерПринятого):

  1. Узел — ссылка на элемент плана обмена (тип ПланОбменаСсылка или массив ссылок). В нашем случае это ЧтениеСообщения.Отправитель.
  2. НомерПринятого — число, соответствующее номеру пакета, который успешно получил удаленный узел. Значение извлекается из заголовка сообщения через свойство ЧтениеСообщения.НомерПринятого.

Важные нюансы и скрытые проблемы при очистке

Выясним причины, по которым метод УдалитьРегистрациюИзменений с указанием номера сообщения может не сработать:

  1. Номер сообщения при выгрузке не был привязан к записям. Метод очистки удаляет только те строки таблицы регистрации, у которых номер сообщения не равен NULL и меньше либо равен переданному значению. Чтобы номер проставился в таблице изменений, на стороне отправки метод выборки должен вызываться строго с передачей номера сообщения: ПланыОбмена.ВыбратьИзменения(Узел, ЗаписьСообщения.НомерСообщения); Если вызвать ПланыОбмена.ВыбратьИзменения(Узел) без второго параметра, номер сообщения останется NULL, и квитирование не сможет определить, какие именно записи подлежат удалению.
  2. Повторное изменение объекта до прихода квитанции. Если объект был выгружен в сообщении №1, но до момента получения ответа пользователь изменил этот объект в базе, платформа автоматически сбрасывает номер сообщения у этой записи в NULL. При получении квитанции по пакету №1 регистрация этого измененного объекта удалена не будет. Это штатное поведение платформы, гарантирующее актуальность данных: более свежая версия объекта гарантированно уйдет в следующем пакете.
  3. Отсутствие свойства ОбменДанными.Загрузка = Истина. Если при записи загружаемого объекта не выставить флаг загрузки, объект запишется в обычном пользовательском режиме. Это приведет к срабатыванию механизмов авторегистрации: объект снова зарегистрируется на узле-отправителе, порождая бесконечное зацикливание передачи одних и тех же данных («эхо-эффект»).

Варианты полной или выборочной очистки регистрации

Если в архитектуре вашего обмена не требуется строгий контроль по номерам пакетов, платформа предоставляет альтернативные варианты вызова метода УдалитьРегистрациюИзменений:

  1. Полная очистка всех изменений для узла:
    
    // Удаляет абсолютно всю регистрацию по узлу без учета номеров пакетов
    ПланыОбмена.УдалитьРегистрациюИзменений(Узел);
    
  2. Выборочное удаление конкретного объекта или массива:
    
    // Удаляет регистрацию конкретного справочника или документа
    ПланыОбмена.УдалитьРегистрациюИзменений(Узел, СсылкаНаОбъект);
    
    // Либо по массиву ссылок
    ПланыОбмена.УдалитьРегистрациюИзменений(Узел, МассивСсылок);
    
  3. Удаление регистрации по конкретному типу метаданных:
    
    // Удаляет регистрацию для всех элементов справочника Контрагенты
    ПланыОбмена.УдалитьРегистрациюИзменений(Узел, Метаданные.Справочники.Контрагенты);
    

Таким образом, для корректной очистки доставленных данных в самописном обмене необходимо синхронизировать два шага: выгружать изменения с фиксацией ЗаписьСообщения.НомерСообщения и при получении ответа удалять регистрацию через ЧтениеСообщения.НомерПринятого.

← На главную