При организации распределенных информационных баз (РИБ) или обменов данными по произвольным правилам часто возникает архитектурная задача: настроить односторонний поток данных. Типичный пример — создание базы-копии для построения тяжелых аналитических отчетов. В такую базу данные должны регулярно поступать из центрального (главного) узла, однако сама копия не должна передавать обратно никаких изменений. При этом для корректной работы механизмов обмена платформа 1С:Предприятие требует регулярной отправки квитанций подтверждения приема пакетов, иначе в главном узле бесконечно растут таблицы регистрации изменений.
Разберем подробно, почему возникает эта проблема, какие подводные камни существуют при стандартной авторегистрации и какими способами можно полностью исключить или автоматически очищать регистрацию изменений в подчиненной базе.
Когда для плана обмена включена авторегистрация объектов (справочников, документов, регистров), любое изменение данных пользователями или фоновыми регламентными заданиями в подчиненной базе автоматически фиксируется в системных таблицах изменений. Если подчиненный узел выгружает эти данные главному, могут возникнуть следующие нежелательные последствия:
Рассмотрим основные и наиболее эффективные варианты решения этой задачи — от простых до программно безупречных.
Это один из самых компактных способов, не требующий создания внешних обработок и дополнительных расписаний. В модуле плана обмена платформы 1С предусмотрен предопределенный обработчик событий ПриОтправкеДанныхГлавному. Он вызывается платформой для каждого зарегистрированного объекта перед помещением его в файл сообщения обмена.
Проанализируем ключевую тонкость: в параметре ОтправкаЭлемента обработчика доступно перечисление ОтправкаЭлементаДанных. Существует принципиальная разница между значениями Игнорировать и Удалить:
ОтправкаЭлементаДанных.Игнорировать: платформа пропускает запись объекта в исходящий XML-пакет, но оставляет запись в таблице регистрации изменений. При следующем сеансе выгрузки платформа снова считает эти объекты из базы, что со временем приведет к катастрофическому замедлению процесса выгрузки.ОтправкаЭлементаДанных.Удалить: платформа не выгружает объект в пакет и одновременно автоматически удаляет запись о его изменении из таблицы регистрации.Посмотрим на пример реализации в модуле плана обмена подчиненного узла:
Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента)
// Безусловно отменяем отправку и снимаем объект с регистрации изменений
ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить;
КонецПроцедуры
Если требуется фильтровать отправку только для конкретных типов метаданных, код можно дополнить проверкой типа:
Процедура ПриОтправкеДанныхГлавному(ЭлементДанных, ОтправкаЭлемента)
// Запрещаем выгрузку для всех документов и регистров
Если ОбщегоНазначения.ЭтоДокумент(ЭлементДанных)
Или ОбщегоНазначения.ЭтоРегистр(ЭлементДанных) Тогда
ОтправкаЭлемента = ОтправкаЭлементаДанных.Удалить;
КонецЕсли;
КонецПроцедуры
При таком подходе при первой же штатной процедуре обмена все накопившиеся изменения будут корректно сброшены, а в исходящий файл запишется только заголовок сообщения с подтверждением принятых номеров пакетов.
Если мы хотим, чтобы таблицы регистрации изменений в подчиненной базе всегда оставались абсолютно пустыми и система не тратила ресурсы на запись и последующее удаление регистраций, разберем решение через подписки на события.
Создадим общую подписку на событие ПередЗаписью для всех объектов конфигурации, включенных в план обмена. В обработчике проверим, является ли текущая база подчиненной (проверяется наличие главного узла через функцию ПланыОбмена.ГлавныйУзел()), и отключим автозаполнение получателей:
Процедура ОтключитьРегистрациюВПодчиненномУзлеПередЗаписью(Источник, Отказ) Экспорт
// Если текущий узел является подчиненным по отношению к какому-либо узлу
Если ЗначениеЗаполнено(ПланыОбмена.ГлавныйУзел()) Тогда
// Отключаем автоматическое определение получателей
Источник.ОбменДанными.Получатели.АвтоЗаполнение = Ложь;
// Очищаем список узлов-получателей для текущего объекта
Источник.ОбменДанными.Получатели.Очистить();
КонецЕсли;
КонецПроцедуры
Такой подход полностью предотвращает создание записей в системных таблицах регистрации, снижая нагрузку на дисковую подсистему при интенсивной работе пользователей в базе отчетов.
Если выгрузка данных инициируется регламентным заданием или специальной процедурой, можно выполнить принудительную очистку всех накопленных изменений непосредственно перед формированием пакета подтверждения.
Посмотрим на пример вызова метода УдалитьРегистрациюИзменений для конкретного узла:
Процедура ОчиститьИзмененияПередВыгрузкой(УзелОбмена) Экспорт
// Удаляем всю накопленную регистрацию для главного узла
ПланыОбмена.УдалитьРегистрациюИзменений(УзелОбмена);
КонецПроцедуры
Разберем особенности этого метода:
Метаданные.Справочники.Номенклатура).В сценариях, когда обмен пишется полностью на встроенном языке без использования типовых подсистем, подчиненному узлу достаточно отправить только файл квитанции. Для этого используется объект платформы ЗаписьСообщенияОбмена.
Рассмотрим, как сформировать заголовок с подтверждением номера принятого сообщения без выгрузки самих данных:
Процедура СформироватьПустоеСообщениеПодтверждения(УзелГлавный, ПутьКФайлу)
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.ОткрытьФайл(ПутьКФайлу);
ЗаписьСообщения = ПланыОбмена.СоздатьЗаписьСообщения();
ЗаписьСообщения.НачатьЗапись(ЗаписьXML, УзелГлавный);
// Тело сообщения оставляем пустым, данные не записываем
ЗаписьСообщения.ЗакончитьЗапись();
ЗаписьXML.Закрыть();
КонецПроцедуры
Когда главный узел прочитает этот файл через ЧтениеСообщенияОбмена, он обновит номер принятого сообщения и автоматически очистит у себя очередь изменений, которые были доставлены подчиненному узлу ранее.
Помимо программного управления механизмом планов обмена, при создании баз-копий для отчетов полезно применять системные ограничения:
Выбор конкретного метода зависит от архитектуры вашей системы: для типовых конфигураций проще всего использовать присвоение ОтправкаЭлементаДанных.Удалить в событии ПриОтправкеДанныхГлавному, а для высоконагруженных систем — отключать автозаполнение получателей через подписку на событие ПередЗаписью.