Почему документы пропадают из регистрации плана обмена и как найти причину

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

Работа с планами обмена в 1С — это фундамент любой системы синхронизации данных. Однако даже в «простых и надежных» самописных механизмах программисты сталкиваются с ситуацией, когда часть документов (обычно 1–5%) не попадает в базу-приемник. Причина всегда одна: запись либо не зарегистрировалась в плане обмена, либо была очищена до момента фактической отправки. Разберем подробно, какие подводные камни таят в себе планы обмена и как локализовать «плавающую» ошибку в высоконагруженной системе.

Анализ механизма регистрации: где искать слабое звено

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

Для этого применим метод расширенного логирования. Мы не можем постоянно сидеть в отладчике на «проде», поэтому заставим систему саму фиксировать все важные шаги. Нам нужно создать механизм, который будет записывать в журнал регистрации (или в отдельный регистр сведений) факт регистрации изменения и факт его удаления.

Важный нюанс: логировать нужно не только факт вызова процедуры, но и контекст. Рассмотрим пример кода, который стоит внедрить в точки регистрации изменений:


Процедура ЗарегистрироватьИзменениеДокумента(Источник) Экспорт
    // Проверяем, не установлена ли блокировка обмена
    Если Источник.ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    Узел = ПланыОбмена.СинхронизацияДанных.НайтиПоКоду("Приемник");
    Если НЕ Узел.Пустая() Тогда
        ПланыОбмена.ЗарегистрироватьИзменения(Узел, Источник.Ссылка);
        
        // Логируем для отладки
        ЗаписьЖурналаРегистрации("ОбменДанными.Регистрация",
            УровеньЖурналаРегистрации.Информация,
            Источник.Метаданные(),
            Источник.Ссылка,
            "Зарегистрировано изменение для узла: " + Строка(Узел));
    КонецЕсли;
КонецПроцедуры

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

Транзакционные коллизии и веб-сервисы

Проанализируем логику очистки регистрации, описанную в теме: база-приемник после записи документа вызывает веб-сервис источника, который выполняет УдалитьРегистрациюИзменений. Здесь кроется самый опасный «подводный камень» — незавершенные транзакции.

Представим сценарий:

  1. База-приемник начинает транзакцию записи документа.
  2. Документ записан в базу, но транзакция еще не зафиксирована (Commit).
  3. Приемник вызывает веб-сервис источника: «Я всё получил, удаляй!».
  4. Источник удаляет регистрацию.
  5. В базе-приемнике происходит сбой (например, ошибка в коде после записи или блокировка СУБД) и транзакция откатывается (Rollback).

Результат: в источнике регистрации больше нет, а в приемнике объект так и не появился. Чтобы избежать этого, вызов очистки должен происходить строго вне транзакции записи в приемнике, только после успешного подтверждения фиксации данных.

Технические нюансы метода УдалитьРегистрациюИзменений

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

Блокировки в SQL и режим RCSI

При работе с большими объемами данных (десятки тысяч документов) проблема может переместиться на уровень СУБД. Таблицы изменений (имеющие префикс _Chng в SQL) подвержены эскалации блокировок. Проанализируем ситуацию:

Когда выполняется массовая регистрация, SQL Server может заблокировать всю таблицу изменений целиком. Если в этот же момент веб-сервис очистки пытается выполнить запрос к этой таблице, он может получить ошибку блокировки. Если в коде 1С не предусмотрен повтор операции при блокировке, регистрация останется или, в худшем случае, запрос вернет пустой результат из-за специфики уровней изоляции (например, если используется Read Committed Snapshot), и логика решит, что удалять нечего.

Рекомендации по стабилизации обмена

Чтобы исключить потерю 1–5% документов, рекомендуем выполнить следующие шаги:

  1. Измените событие регистрации: Если регистрация происходит в ПриЗаписи, убедитесь, что она выполняется в самом конце процедуры, когда основные проверки пройдены. Еще лучше использовать подписку ПриЗаписи с проверкой ДополнительныеСвойства, чтобы избежать повторных срабатываний.
  2. Внедрите контроль номеров сообщений: Не удаляйте регистрацию «безусловно» по ссылке. Используйте штатный механизм: при выгрузке фиксируйте НомерСообщения, а при получении квитанции удаляйте регистрацию только по этому номеру (метод УдалитьРегистрациюИзменений(Узел, НомерСообщения)). Это гарантирует, что если документ был изменен в источнике после отправки, но до получения ответа, его новая регистрация не будет затерта.
  3. Используйте идентификатор транзакции: Для отладки записывайте в логи НомерТранзакцииДомена(). Это позволит сопоставить действия в источнике и приемнике и понять, не произошло ли удаление раньше фиксации.
  4. Проверка существования записи: Перед вызовом удаления регистрации в веб-сервисе, добавьте проверку:
    
    Запрос = Новый Запрос;
    Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 1 ИЗ Документ.ВашДокумент.Изменения ГДЕ Узел = &Узел И Ссылка = &Ссылка";
    // ... установка параметров
    Если НЕ Запрос.Выполнить().Пустой() Тогда
        ПланыОбмена.УдалитьРегистрациюИзменений(Узел, Ссылка);
    КонецЕсли;
    
    Это поможет понять, была ли регистрация в принципе на момент вызова очистки.

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

← На главную