Почему я решил писать эту статью?
Какие способы регистрации изменений есть в платформе?
Недостатки старых подходов при организации интеграций.
На что способна История данных?
Создадим конфигурацию с расширениями.
Включим программно Историю данных.
Пример 1: Первое знакомство с пост обработкой.
Пример 3: Включаем автоматику, чистку отработанных версий и отключаем ненужные реквизиты.
Почему я решил писать эту статью?
1 Я уже рассказывал, как в 2021 году провел 100 собеседований за 3 месяца и увидел, что 50% собеседуемых не слышали про Историю данных, 20% что-то слышали, но не знают, чем она отличается от БСП Версионирования данных.
Как по мне — это пугающая статистика.
В связи с чем я поставил себе цель на 2023 год – «Максимально донести информацию по данной технологии платформы». Я спланировал все кубики пазла и это последний кубик, который я планировал рассказать, как часть доклада. В докладе был пункт «Плановый переход с планов обмена на историю данных». Доклада не случилось, поэтому последний кубик будет в виде статьи.
2 Спойлер. Начал писать цикл статей по интеграции, связанных с Шиной, и пришел к выводу, что без данной статьи получится очень громоздко.
Какие способы регистрации изменений есть в платформе?
- Первое, что приходит в голову, «Планы обмена».
- Второе, различные вариации на тему Регистров сведений.
Есть варианты отлова изменений прямо на SQL, но это уже совсем другая история.
Для начала я рекомендую почитать или посмотреть выступление Дмитрия Жичкина, так как он уже подробно описал архитектуру и основные недостатки планов обмена -> Планы обмена 1С
На последнем INFOSTART EVENT 2023 он же выступал с докладом «Тюнинг планов обмена», в котором пытался оживить Планы обмена за счет своей разработки DaJet. Уверен многие из нас делали регистрацию изменений на Регистрах сведений и часть проблем уходило, но проблем все равно много.
Недостатки старых подходов при организации интеграций.
- Блокировки. Про подробности читайте статью -> Планы обмена 1С
- Регистрируется сам факт изменения.
Мы не знаем, что поменялось в объекте, соответственно даже если поменялся только комментарий, мы потащим объект целиком, даже если в объекте может быть много таблиц.
Представьте, что вы приходите к врачу за справкой, а с вас требуют все ваши документы, которые у вас появились за все время жизни, плюсом требуют рассказать все, чем вы занимаетесь, про ваши хобби, вкусовые предпочтения и т.д.
- Все или ничего.
Нельзя собирать изменения только по части объекта.
Хотя… Можно, но для этого в подписке «ПередЗаписью» придётся сделать проверку изменений до и после только по определенным реквизитам, а потом еще дорабатывать, когда пересмотрите свои взгляды на первоначальные настройки.
- Мы не знаем автора изменений.
Это вытекает из предыдущих недостатков. На помощь может прийти Версионирование объектов или можно изобразить свой велосипед.
- Последовательность.
Мы не знаем, в какой последовательности изменялись данные.
Это решается при использовании Регистров сведений и поля а ля timestamp.
Либо выставляется приоритет загрузки\выгрузки, но этот велосипед устарел…
- Изменение состава через доработки.
Хотите регистрировать новый объект?
Добавьте его в состав.
Хотите, чтобы он попадал в обмен не всегда?
Необходимо запретить Авторегистрацию и написать код в «ПередЗаписью».
И, кстати, не забудьте дать права.
И только после обновления конфигурации и добавления узла регистрация по объекту начнет работать регистрация изменений.
- Нежелательно использовать в расширении.
Если у вас План обмена в расширении и помимо этого расширения есть еще другие расширения… Объект из расширения трудно будет зарегистрировать на Плане обмена из другого расширения.
- Узел = приемник.
Тут вопросы фильтрации, сериализации, настройки подключения и прочие недостатки. Каждый новый Узел увеличивает нагрузку на основную базу (Источник) за счет повторяемых операций.
По большему счету один и тот же элемент будет сериализовываться для каждого Узла и чем больше узлов, тем больше повторений.
Новые фильтры также ведут к доработкам и монстрообразию.
Фильтрация происходит «ПередЗаписью», соответственно, чем больше фильтров и узлов, тем дольше происходит запись объекта.
При этом, чтобы сократить трудозатраты на фильтрацию, бывает, делают общий узел для регистрации всех изменений. Данные с общего узла разгребают и фильтруют на другие узлы отдельным регламентом. Что увеличивает временной лаг.
Настройки подключений хранятся на узлах, что я тоже считаю минусом. Для малого числа баз и обменов это не принципиально, но чем больше обменов, тем больше контроля.
- Размер сообщений.
За счет того, что мы не знаем, что изменилось в объекте, мы каждый раз будем гонять объект целиком, что пагубно влияет на размер сообщений.
Размер сообщения бывает настолько большой, что приходится бить его на порции, при этом сообщение можно прочитать только собрав все порции воедино.
Плюсы:
- Быстрый старт.
- Легки в использовании.
- Все уже придумано до нас и известны все недостатки.
«Если планы обмена такие плохие, тогда что делать?»
Они не плохие, они просто не про крупные организации с большим документооборотом.
Позвольте показать вам еще один вариант регистрации изменений.
Ну вот, теперь пора переходить к рассказу о Истории данных.
На что способна История данных?
Первоначально История данных повторяла тот же функционал, который делала подсистема Версионирования, но заимела ряд киллер-фич, о которых я рассказывал в статье Версионирование объектов VS История данных. В платформе 8.3.15 было добавлено то, чего в Версионировании нет и никогда не будет. Было добавлено то, что позволяет полноценно использовать историю данных для регистрации изменений.
«В версии платформы 8.3.15 появилась Очередь обработки после записи истории данных»
Дальше поговорим о том «Для чего это и как этим пользоваться».
Для начала посмотрим, как выглядит «Жизненный цикл изменений», а дальше разберем, что к чему.
1 При изменении объекта данные об изменении попадают в таблицу Очередь истории данных [DataHistoryQueue0]. Происходит это после события «ПриЗаписи». Данные лежат там до тех пор, пока не произойдет Обновление истории.
!!!Важно!!!
- Очередь истории данных ведется только по объектам, у которых включена История данных.
- История данных может быть включена как в конфигураторе, так и программно.
Для включения в конфигураторе нужно выбрать у «Истории данных» значение Использовать.
Для программного включения можно использовать обработку из платформы 8.3.24.
Вытащить ее можно простым кодом:
КопироватьФайл("v8res://mngbase/StandardDataChangeHistory.epf ", "C:\StandardDataChangeHistory.epf");
Либо забрать из статьи История данных. Изменения в платформе 8.3.24
Либо взять бесплатную обработку с более богатым функционалом Настройка состава "Истории данных"
2 Обновление истории и обработки после записи версии может производиться автоматически, программно или при регламенте.
Версии истории данных хранятся в [DataHistoryVersions], происходит это при следующих действиях:
- Для автоматического создания через конфигуратор необходимо включить «Обновлять историю данных сразу после записи»
- Можно включить программно. Для этого в «ПередЗаписью» или «ПриЗаписи» нужно добавить код:
Источник.ЗаписьИсторииДанных.ОбновлятьИсториюСразуПослеЗаписи = Истина;
- Если автоматическое создание выключено, необходимо сделать регламентное задание со следующим кодом:
ИсторияДанных.ОбновитьИсторию();
Очередь обработки после записи истории данных хранится в [DataHistoryAfterWriteQueue], данные попадают туда при следующих действиях:
- Для автоматического создания через конфигуратор необходимо включить «Выполнять обработку после записи версии истории данных»
- Можно включить программно. Для этого в «ПередЗаписью» или «ПриЗаписи» нужно добавить код:
Источник.ЗаписьИсторииДанных.ВыполнятьОбработкуПослеЗаписиВерсии = Истина;
- Если автоматическое создание выключено, необходимо сделать регламентное задание со следующим кодом:
ИсторияДанных.ВыполнитьОбработкуПослеЗаписиВерсий();
Либо в регламенте с ОбновитьИсторию() прописать параметр «ВыполнитьОбработкуПослеЗаписиВерсий»:
ОбновитьИсторию(<ВыполнитьОбработкуПослеЗаписиВерсий>, <АвтоУдалениеИзОбработкиПослеЗаписиВерсий>)
Параметры:
<ВыполнитьОбработкуПослеЗаписиВерсий> (необязательный)
Тип: Булево.
Если Истина - после выполнения обновления истории выполнится обработка после записи версий истории данных.
Обработка после записи истории данных происходит в менеджере объектов:
Можно выбрать в подписке на событие:
- РегистрСведенийМенеджер
- ПланСчетовМенеджер
- ДокументМенеджер
- БизнесПроцессМенеджер
- ПланВидовРасчетаМенеджер
- ЗадачаМенеджер
- ПланВидовХарактеристикМенеджер
- СправочникМенеджер
На момент написания статьи в подписке на событие не дает выбрать:
- ПланОбменаМенеджер
- КонстантаМенеджер
Киллер-фича №0: Создание версий происходит на уровне платформы, а пост обработка работает с уже созданными версиями в фоновом задании минуя блокировки, которые происходят перед регистрацией у Планов обменов.
3 Важно не забыть удалить данные из обработчика после того, как по ним проведены нужные действия.
Для этого нужно выполнить код:
ИсторияДанных.УдалитьИзОбработкиПослеЗаписиВерсий(Данные, НомерВерсии);
Если «НомерВерсии» не указать, тогда удалятся все версии.
Давайте на практике посмотрим, что может История данных.
Создадим конфигурацию с расширениями.
Создаем пустую базу. Добавляем в нее справочник «СправочникКонфигурации» с реквизитами:
- ПростоТекст – Строка (250)
- Ненужный – Строка (10)
Табличная часть «ТаблицаТекста» с реквизитом:
- ТекстТаблицы – Строка (200)
Создаем 2 Расширения:
- Расширение1 со справочником «СправочникРасширения1» повторяющий структуру «СправочникаКонфигурации»
- Расширение2 со справочником «СправочникРасширения2» повторяющий структуру «СправочникаКонфигурации»
Нам понадобятся еще Подписки на события «ПередЗаписью» с источником (СправочникОбъект) и «ОбработкаПослеЗаписиВерсийИсторииДанных» с источником (СправочникМенеджер), ну и соответственно модуль для хранения кода обработчиков.
Я буду использовать свое универсальное решение для скорости создания подписок и изменения кода без вмешательства в конфигурацию.
Код я буду выполнять во внешней обработке:
- ПередЗаписью пока без кода.
- ОбработкаПослеЗаписиВерсийИсторииДанных пока без кода.
Также понадобится регламент или обработка с обновлением истории:
ИсторияДанных.ОбновитьИсторию();
И регламент или обработка с выполнением обработки после записи версий:
ИсторияДанных.ВыполнитьОбработкуПослеЗаписиВерсий();
Включим программно Историю данных.
Создадим элемент справочника «СправочникКонфигурации» до того, как включим Историю данных. Нужно, чтобы продемонстрировать в первом примере «ВидыИзмененияДанных».
Я буду использовать бесплатную обработку Настройка состава "Истории данных" и для начала включу историю данных по объектам целиком.
Киллер-фича №1: Мы только что включили Историю данных программно, нам не потребовалось заходить в конфигуратор и прописывать состав. Также просто мы можем и отключить историю. Планы обмена, Регистры сведений так не умеют. В планах обмена нужно изменять состав, а в регистрах добавлять в составной тип новое значение, и без конфигуратора не обойтись.
Киллер-фича №2: Мы только что включили Историю данных программно, для объектов из двух расширений. План обмена и Регистры сведений так смогут только если вы их добавите в основную конфигурацию и то не без телодвижений и обновления конфигурации. Если вы добавите План обмена или Регистр сведений в расширение, тогда вы не сможете добавить в состав объект из другого расширения.
Пример 1: Первое знакомство с пост обработкой.
В данном примере мы накопим небольшое количество изменений и запустим пост обработку программно.
Создадим еще один Элемент в справочнике «СправочникКонфигурации»
В обработчике «ОбработкаПослеЗаписиВерсийИсторииДанных» поставим точку останова и подключим в отладке остановку по фоновым заданиям.
Запускаем ОбновитьИсторию(), а следом ВыполнитьОбработкуПослеЗаписиВерсий();
Обратите внимание - прилетел элемент 2, который создан после включения Истории данных, и вид изменения у него «Добавление».
Также мы видим:
- Пользователя, который сделал изменение (у меня база без пользователей, поэтому имя пустое).
- Дату и время создания изменения
- Номер версии изменения и самая главная фишка «Различия версий» и данные конкретно этой версии.
Давайте теперь изменим элемент, созданный до включения Истории данных, и тот, что был создан после.
Элемент 1. Поменял текст в реквизите «Ненужен» и добавил строку ТЗ.
Элемент 2. Поменял строки местами и изменил текст в реквизите «Ненужен»
Запускаем ОбновитьИсторию(), а следом ВыполнитьОбработкуПослеЗаписиВерсий();
Обратите внимание на следующее:
- Первый элемент был добавлен до второго элемента, но тогда история данных была выключена, а изменен после того, как был добавлен второй. Мы видим, как работает сортировка при пост обработке:
- По дате
- По номеру версии
- Второй момент, на который нужно обратить внимание. Вид изменений у объекта, созданного до включения версии, является «Изменение», хотя данная версия ничем не отличается от добавления первой версии.
Давайте теперь посмотрим на вторую версию элемента 2:
Мы видим в «РазличияВерсий» только измененные данные, при этом мы видим, что было до и что стало после.
По табличной части мы меняли местами строки и именно об этом нам и сообщают.
Киллер-фича №3: При создании версии мы видим пользователя, который изменил объект. План обмена так не умеет, Регистр сведений можно научить этому навыку.
Киллер-фича №4: При создании версии мы видим дату и время изменения. План обмена так не умеет, Регистр сведений можно научить этому навыку.
Киллер-фича №5: Мы видим версию и изменения, сделанные в конкретной версии. Видим значения до изменения. План обмена так не умеет, нечто подобное умеет подсистема Версионирования из БСП, но она хранит версию целиком и изменения можно поймать только путем сравнения версий.
Допустим, нам нужно добавлять в версию значение, которое отсутствует в объекте, или вы хотите видеть комментарий у версии, что для этого нужно сделать?
В подписку перед записью добавим следующий код:
Источник.ЗаписьИсторииДанных.ДобавитьДополнительныеДанные("ТекущаяДатаСеанса", ТекущаяДатаСеанса(), "Текущая дата сеанса");
Теперь давайте сохраним элемент 2 и пару секунд постоим на точке останова, на добавленной строчке:
Что у нас в пост обработке?
Мы видим, как мы простым кодом обогатили версию. Мы можем записывать туда любые значения и получать их в пост обработку. Мало того, в отчете о сравнении версий мы все это увидим без малейшей доработки.
Давайте добавим комментарий к версии 3. Напишем «Добавили текущую дату сеанса».
Сделаем небольшую обработку:
Код кнопки «ЗаписатьКомментарий»:
&НаКлиенте
Процедура ЗаписатьКомментарий(Команда)
ЗаписатьКомментарийНаСервере(Данные, Версия, Комментарий);
КонецПроцедуры
&НаСервереБезКонтекста
Процедура ЗаписатьКомментарийНаСервере(Данные, Версия, Комментарий)
ИсторияДанных.ЗаписатьКомментарий(Данные, Версия, Комментарий);
КонецПроцедуры
Также можно создать версию объекта вручную и прописать комментарий.
Код создания версии:
// Процедура - Произвести запись версии
//
// Параметры:
// Данные - БизнесПроцессОбъект,
// ПланВидовРасчетаОбъект,
// ПланСчетовОбъект,
// ПланВидовХарактеристикОбъект,
// ПланОбменаОбъект,
// РегистрСведенийНаборЗаписей,
// КонстантаМенеджерЗначения,
// СправочникОбъект,
// ЗадачаОбъект,
// ДокументОбъект - Объект конфигурации по которому будет создана версия
// ВидИзменения - Строка - "Добавление", "Изменение" или "Удаление"
// Комментарий - Строка - Текст комментария
//
Процедура ЗаписатьВерсию(Данные, ВидИзменения = "Изменение", Комментарий = "Версия записана вручную") Экспорт
ДатаСоздания = ТекущаяДатаСеанса();
ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь() ;
ИсторияДанных.ЗаписатьВерсию(Данные,
ДатаСоздания,
ТекущийПользователь.УникальныйИдентификатор,
ТекущийПользователь.Имя,
ТекущийПользователь.ПолноеИмя,
ВидИзмененияДанных[ВидИзменения],
Комментарий);
КонецПроцедуры
Киллер-фича №6: Мы можем добавлять значения, в версию которых нет в объекте. План обмена так не умеет, Регистр сведений можно научить этому навыку, но это будут доработки.
Киллер-фича №7: Мы можем добавлять комментарий к версии объекта. План обмена так не умеет, Регистр сведений можно научить этому навыку.
Пример 3: Включаем автоматику, чистку отработанных версий и отключаем ненужные реквизиты.
Чтобы не запускать вручную обновление и выполнение пост обработки, «ПередЗаписью» добавим код:
Источник.ЗаписьИсторииДанных.ВыполнятьОбработкуПослеЗаписиВерсии = Истина;
Источник.ЗаписьИсторииДанных.ОбновлятьИсториюСразуПослеЗаписи = Истина;
В пост обработке нужно предусмотреть, чтобы чистились отработанные данные и была возможность пройтись по старым данным, если по ним что-то не отработало.
Примерный код для «ОбработкаПослеЗаписиВерсийИсторииДанных»:
// Соответствии содержит данные и версию для удаления
УдаляемыеДанные = Новый Соответствие;
Для Каждого ТекущаяЗапись Из ИнформацияОЗаписиВерсий Цикл
// Выполняем действия
// Если действия выполнены добавляем в список удаляемых
УдаляемыеДанные.Вставить(ТекущаяЗапись.Данные, ТекущаяЗапись.НомерВерсии);
КонецЦикла;
// Чистим отработанные данные
Для Каждого Данные Из УдаляемыеДанные Цикл
// Если номер не установлен, то из обработки удаляются все версии по указанным данным.
ИсторияДанных.УдалитьИзОбработкиПослеЗаписиВерсий(Данные.Ключ);
КонецЦикла;
Проверим, как работает.
Добавил третью строку в элемент 2 справочника «СправочникКонфигурации» и записал.
Сразу же у нас сработала автоматика, и мы из «ПередЗаписью» прилетели в «ОбработкаПослеЗаписиВерсийИсторииДанных», где произошла чистка отработанных данных из пост обработки.
Наш код работает, двигаемся дальше.
Теперь давайте создадим элементы в расширениях.
Расширение 1.
Расширение 2.
Далее с помощью ранее используемой обработки частично выключим реквизиты в объектах и посмотрим, что из этого получится.
В Расширении1 у справочника отключим реквизит «Ненужный»
В Расширении2 у справочника отключим табличную часть «ТаблицаТекста»
В основной конфигурации у справочника отключим все кроме стандартных реквизитов.
Теперь в «СправочникКонфигурации» у элемента 2 изменим порядок строк и нестандартные реквизиты:
Записываем и смотрим в пост обработке, какие измененные данные прилетели.
Вот так просто мы отключаем сбор изменений по ненужным реквизитам. Соответственно для расширений все отработало точно так же.
Киллер-фича №8: Мы можем отключать сбор изменений по ненужным реквизитам. Мы можем работать программно как с основной конфигурацией, так и с расширениями. План обмена так не умеет, Регистр сведений можно научить этому навыку, но это будут доработки.
Как вы видите, в платформе для регистрации изменений есть не только Планы обмена и Регистры сведений, но и более тонкий механизм, позволяющий перейти на новый уровень интеграции. Он, есть начиная с 8.3.15, а значит ничего не мешает его использовать. Я показал его основные фишки, дальше дело за вами.
Лично я на текущем месте перешел на историю данных для регистрации изменений.
Полезные статьи по данной тематике:
1 Настройка состава "Истории данных" - Бесплатная обработка по программному включению истории данных.
2 История данных и БСП - Данная статья показывает процесс перехода с Версионирования на Историю данных.
!!!Предупреждение!!! Мы проделывали этот путь у себя на проекте и заметили, что обработка с ИТС не всегда включает Историю данных, а иногда включает не целиком. Из-за этого у нас случались неприятные моменты. Поэтому после переноса лучше перепроверить обработкой из первого пункта и включить все то, что не включилось.
3 Версионирование объектов VS История данных – Сравнение двух конкурирующих механизмов и ковыряние в SQL по части Истории данных. В статье видно, что История данных на данный момент имеет много киллер фич по отношению к Версионированию объектов.
4 История данных. Изменения в платформе 8.3.24 В данной статье я выложил типовую обработку из платформы 8.3.24 и сравнил ее со своей из первого пункта.
5 Неочевидный баг Истории данных, убивающий rphost В данной статье я рассказал про неприятный баг, который мы поймали. Также в комментариях к статье можно обнаружить лечение еще одного бага, за что огромное спасибо участникам сообщества.
6 Планы обмена 1С - Подробная статья по устройству Планов обмена.
7 Интегрируй это - Замечательный доклад, в котором упоминается История данных и подписка «ОбработкаПослеЗаписиВерсииИсторииДанных»
У меня есть к Вам пара вопросов. Напишите в комментариях, интересны ли вам следующие темы:
1 Было бы вам интересно сделать сквозной пример (frontend и backend) на NodeJS + Express + React и т.д.?
2 Интересно было бы почитать цикл статей под названием «Добро пожаловать на борт?», затрагивающие следующие темы:
- Поиск работы. Поиск работников. Взгляд с двух сторон.
- Собеседование в удовольствие. На что обратить внимание, как не превратить собеседование в допрос. Тайминг, вопросы. Плюсом могу запросить честные отзывы собеседуемых.
- Программисты из «Желтой коробочки», хорошо это или плохо. Быстро, Дешево, Криво или почему Фирма 1с убивает ИТшников?
- Виды сотрудников. Виды руководителей.
- Полезный и вредный опыт.
- Виды работодателей. От галеры до бюрократической ямы.
Если я увижу интерес, то спланирую график по оформлению материала в ряд статей, а может, замахнусь на канал с видео.
На этом статью заканчиваю и ставлю еще одну галочку в выполненные задумки.
Надеюсь, статья была вам полезна. Желаю всем профессионального роста и интересных задач!