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

Для большего понимания попытаемся отобразить на схеме одновременно все варианты:
1) Отсутствие собственных обработчиков обновления
2) Метод предлагаемый документацией БСП
3) Метод с использованием расширения

Технические детали
Всего потребовалось расширить три модуля:
1) Служебный модуль подсистемы "Обновление ИБ" для добавления условия при смене версии расширения
2) Переопределяемый модуль для добавления подсистемы расширения
3) Модуль подсистемы основной конфигурации для добавления нашей подсистемы в качестве требуемой для основной

Тексты модулей:
ОбновлениеИнсформационнойБазыРАСШ
#Область ПрограммныйИнтерфейс
#Область ДляВызоваИзДругихПодсистем
// СтандартныеПодсистемы.ОбновлениеВерсииИБ
////////////////////////////////////////////////////////////////////////////////
// Сведения о библиотеке (или конфигурации).
// Заполняет основные сведения о библиотеке или основной конфигурации.
// Библиотека, имя которой имя совпадает с именем конфигурации в метаданных, определяется как основная конфигурация.
//
// Параметры:
// Описание - Структура:
//
// * Имя - Строка - имя библиотеки, например, "СтандартныеПодсистемы".
// * Версия - Строка - версия в формате из 4-х цифр, например, "2.1.3.1".
//
// * ИдентификаторИнтернетПоддержки - Строка - уникальное имя программы в сервисах Интернет-поддержки.
// * ТребуемыеПодсистемы - Массив - имена других библиотек (Строка), от которых зависит данная библиотека.
// Обработчики обновления таких библиотек должны быть вызваны ранее
// обработчиков обновления данной библиотеки.
// При циклических зависимостях или, напротив, отсутствии каких-либо зависимостей,
// порядок вызова обработчиков обновления определяется порядком добавления модулей
// в процедуре ПриДобавленииПодсистем общего модуля
// ПодсистемыКонфигурацииПереопределяемый.
// * РежимВыполненияОтложенныхОбработчиков - Строка - "Последовательно" - отложенные обработчики обновления выполняются
// последовательно в интервале от номера версии информационной базы до номера
// версии конфигурации включительно или "Параллельно" - отложенный обработчик после
// обработки первой порции данных передает управление следующему обработчику, а после
// выполнения последнего обработчика цикл повторяется заново.
// * ЗаполнятьДанныеНовыхПодсистемПриПереходеСДругойПрограммы - Булево - если установить Истина, то при переходе с
// другой программы будут автоматически выполнены обработчики начального заполнения
// новых подсистем. При описании обработчика обновления можно при необходимости
// отключить его выполнение, указав свойство НеВыполнятьПриПереходеСДругойПрограммы.
//
Процедура ПриДобавленииПодсистемы(Описание) Экспорт
Расширение = расшОбщегоНазначенияПовтИсп.ТекущееРасширение();
Описание.Имя = Расширение.Имя;
Описание.Версия = Расширение.Версия;
КонецПроцедуры
////////////////////////////////////////////////////////////////////////////////
// Обработчики обновления информационной базы.
// Добавляет в список процедуры-обработчики обновления данных ИБ
// для всех поддерживаемых версий библиотеки или конфигурации.
// Вызывается перед началом обновления данных ИБ для построения плана обновления.
//
// Параметры:
// Обработчики - см. ОбновлениеИнформационнойБазы.НоваяТаблицаОбработчиковОбновления
//
// Пример:
// Для добавления своей процедуры-обработчика в список:
// Обработчик = Обработчики.Добавить();
// Обработчик.Версия = "1.1.0.0";
// Обработчик.Процедура = "ОбновлениеИБ.ПерейтиНаВерсию_1_1_0_0";
// Обработчик.РежимВыполнения = "Оперативно";
//
Процедура ПриДобавленииОбработчиковОбновления(Обработчики) Экспорт
// Добавляем наши обработчики
КонецПроцедуры
// См. ОбновлениеИнформационнойБазыПереопределяемый.ПередОбновлениемИнформационнойБазы.
Процедура ПередОбновлениемИнформационнойБазы() Экспорт
КонецПроцедуры
// Вызывается после завершения обновления данных ИБ.
// В зависимости от тех или иных условий можно отключить штатное открытие формы
// с описанием изменений в новой версии программы при первом входе в нее (после обновления),
// а также выполнить другие действия.
//
// Не рекомендуется выполнять в данной процедуре какую-либо обработку данных.
// Такие процедуры следует оформлять штатными обработчиками обновления, выполняемыми на каждую версию "*".
//
// Параметры:
// ПредыдущаяВерсия - Строка - версия до обновления. "0.0.0.0" для "пустой" ИБ.
// ТекущаяВерсия - Строка - версия после обновления. Как правило, соответствует Метаданные.Версия.
// ВыполненныеОбработчики - ДеревоЗначений:
// * НачальноеЗаполнение - Булево - если Истина, то обработчик должен срабатывать при запуске на "пустой" базе.
// * Версия - Строка - например, "2.1.3.39". Номер версии конфигурации, при переходе
// на которую должна быть выполнена процедура-обработчик обновления.
// Если указана пустая строка, то это обработчик только для начального заполнения
// (должно быть указано свойство НачальноеЗаполнение).
// * Процедура - Строка - полное имя процедуры-обработчика обновления/начального заполнения.
// Например, "ОбновлениеИнформационнойБазыУПП.ЗаполнитьНовыйРеквизит"
// Обязательно должна быть экспортной.
// * РежимВыполнения - Строка - режим выполнения обработчика обновления. Допустимые значения:
// Монопольно, Отложенно, Оперативно. Если значение не заполнено, обработчик
// считается монопольным.
// * ОбщиеДанные - Булево - если Истина, то обработчик должен срабатывать до
// выполнения любых обработчиков, использующих разделенные данные.
// Допустимо указывать только для обработчиков с режимом выполнения Монопольно и Оперативно.
// Если указать значение Истина для обработчика с режимом
// выполнения Отложенно, будет выдано исключение.
// * УправлениеОбработчиками - Булево - если Истина, то обработчик должен иметь параметр типа Структура, в котором
// есть свойство РазделенныеОбработчики - таблица значений со структурой,
// возвращаемой этой функцией.
// При этом колонка Версия игнорируется. В случае необходимости выполнения
// разделенного обработчика в данную таблицу необходимо добавить строку с
// описанием процедуры обработчика.
// Имеет смысл только для обязательных (Версия = *) обработчиков обновления
// с установленным флагом ОбщиеДанные.
// * Комментарий - Строка - описание действий, выполняемых обработчиком обновления.
// * Идентификатор - УникальныйИдентификатор - необходимо заполнять для обработчиков отложенного обновления,
// для остальных заполнение не требуется. Требуется для идентификации
// обработчика в случае его переименования.
//
// * БлокируемыеОбъекты - Строка - необходимо заполнять для обработчиков отложенного обновления,
// для остальных заполнение не требуется. Полные имена объектов через запятую,
// которые следует блокировать от изменения до завершения процедуры обработки данных.
// Если заполнено, то также требуется заполнить и свойство ПроцедураПроверки.
// * ПроцедураПроверки - Строка - необходимо заполнять для обработчиков отложенного обновления,
// для остальных заполнение не требуется. Имя функции, которая для переданного объекта
// определяет, завершена ли для него процедура обработки данных.
// Если переданный объект обработан, то следует вернуть значение Истина.
// Вызывается из процедуры ОбновлениеИнформационнойБазы.ПроверитьОбъектОбработан.
// Параметры, передаваемые в функцию:
// Параметры - см. ОбновлениеИнформационнойБазы.МетаданныеИОтборПоДанным.
// * ПроцедураЗаполненияДанныхОбновления - Строка - указывается процедура, которая регистрирует данные,
// подлежащие обновлению данным обработчиком.
// * ЗапускатьТолькоВГлавномУзле - Булево - только для обработчиков отложенного обновления с режимом выполнения Параллельно.
// Указать Истина, если обработчик обновления должен выполняться только в главном
// узле РИБ.
// * ЗапускатьИВПодчиненномУзлеРИБСФильтрами - Булево - только для обработчиков отложенного обновления с режимом
// выполнения Параллельно.
// Указать Истина, если обработчик обновления должен также выполняться в
// подчиненном узле РИБ с фильтрами.
// * ЧитаемыеОбъекты - Строка - объекты, которые обработчик обновления будет читать при обработке данных.
// * ИзменяемыеОбъекты - Строка - объекты, которые обработчик обновления будет изменять при обработке данных.
// * ПриоритетыВыполнения - ТаблицаЗначений - таблица приоритетов выполнения между отложенными обработчиками,
// изменяющими или читающими одни и те же данные. Подробнее см. в комментарии
// к функции ОбновлениеИнформационнойБазы.ПриоритетыВыполненияОбработчика.
// * ВыполнятьВГруппеОбязательных - Булево - следует указывать, если обработчик требуется
// выполнять в одной группе с обработчиками на версии "*".
// При этом возможно менять порядок выполнения обработчика
// относительно других путем изменения приоритета.
// * Приоритет - Число - для внутреннего использования.
// * МонопольныйРежим - Неопределено
// - Булево - если указано Неопределено, то обработчик
// должен безусловно выполняться в монопольном режиме.
// Для обработчиков перехода на конкретную версию (версия <> *):
// Ложь - обработчик не требует монопольного режима для выполнения.
// Истина - обработчик требует монопольного режима для выполнения.
// Для обязательных обработчиков обновления (Версия = "*"):
// Ложь - обработчик не требует монопольного режима.
// Истина - обработчик может требовать монопольного режима для выполнения.
// В такие обработчики передается параметр типа структура
// со свойством МонопольныйРежим (типа Булево).
// При запуске обработчика в монопольном режиме передается
// значение Истина. В этом случае обработчик должен выполнить
// требуемые действия по обновлению. Изменение параметра
// в теле обработчика игнорируется.
// При запуске обработчика в немонопольном режиме передается
// значение Ложь. В этом случае обработчик не должен вносить никакие
// изменения в ИБ.
// Если в результате анализа выясняется, что обработчику требуется
// изменить данные ИБ, следует установить значение параметра в Истина
// и прекратить выполнение обработчика.
// В этом случае оперативное (немонопольное) обновление ИБ будет
// отменено и будет выдана ошибка с требованием выполнить обновление в
// монопольном режиме.
// ВыводитьОписаниеОбновлений - Булево - если установить Ложь, то не будет открыта форма
// с описанием изменений в новой версии программы. По умолчанию Истина.
// МонопольныйРежим - Булево - признак того, что обновление выполнилось в монопольном режиме.
//
Процедура ПослеОбновленияИнформационнойБазы(Знач ПредыдущаяВерсия, Знач ТекущаяВерсия,
Знач ВыполненныеОбработчики, ВыводитьОписаниеОбновлений, Знач МонопольныйРежим) Экспорт
КонецПроцедуры
// См. ОбновлениеИнформационнойБазыПереопределяемый.ПриПодготовкеМакетаОписанияОбновлений.
Процедура ПриПодготовкеМакетаОписанияОбновлений(Знач Макет) Экспорт
КонецПроцедуры
#КонецОбласти
#КонецОбласти
ОбновлениеИнформационнойБазыСлужебныйПовтИсп
&Вместо("НеобходимоОбновлениеИнформационнойБазы")
Функция расшНеобходимоОбновлениеИнформационнойБазы()
Результат = ПродолжитьВызов();
Расширение = расшОбщегоНазначенияПовтИсп.ТекущееРасширение();
Если ОбновлениеИнформационнойБазыСлужебный.НеобходимоВыполнитьОбновление(
Расширение.Версия, ОбновлениеИнформационнойБазыСлужебный.ВерсияИБ(Расширение.Имя)) Тогда
Результат = Истина;
КонецЕсли;
Возврат Результат;
КонецФункции
ОбновлениеИнформационнойБазыУП
&После("ПриДобавленииПодсистемы")
Процедура расшПриДобавленииПодсистемы(Описание)
Расширение = расшОбщегоНазначенияПовтИсп.ТекущееРасширение();
Описание.ТребуемыеПодсистемы.Добавить(Расширение.Имя);
КонецПроцедуры
ПодсистемыКонфигурацииПереопределяемый
&После("ПриДобавленииПодсистем")
Процедура расшПриДобавленииПодсистем(МодулиПодсистем)
МодулиПодсистем.Добавить("ОбновлениеИнсформационнойБазыРАСШ");
КонецПроцедуры
расшОбщегоНазначенияПовтИсп
Функция ТекущееРасширение() Экспорт
Отбор = Новый Структура("Имя", "Расширение");
УстановитьПривилегированныйРежим(Истина);
НайденныеРасширения = РасширенияКонфигурации.Получить(Отбор);
УстановитьПривилегированныйРежим(Ложь);
Расширение = НайденныеРасширения[0];
Возврат Расширение;
КонецФункции
Модуль ОбновлениеИнформационнойБазыУП является модулем подсистемы с именем основной конфигурации, то есть именно эта подсистема, описанная в данном модуле, является "основной".
Итог
Мы рассмотрели подход при котором без изменения корня основной конфигурации мы можем создавать свои обработчики обновления, которые сможем запускать изменяя версию расширения в конфигураторе. Стоит отметить, что и стандартный подход из документации к БСП и рассмотренный нами, обладают одним большим минусом - что бы выполнились наши обработчики, в любом случае требуется и выполнение типовых обработчиков, что может занимать значительное время. К сожалению подсистема БСП "Обновление ИБ" поддерживает только одну "основную" подсистему, связанную с основной конфигурацией по имени. Поэтому мы и выбираем между подходами - сделать "основной" нашу подсистема, а типовую зависимой. Или типовую оставить основной, а нашу добавить в её зависимости.
- Платформа: 1С:Предприятие 8.3 (8.3.25.1546)
- Конфигурация: 1С:ERP Управление предприятием 2 (2.5.21.104)