Известный факт, что при обмене данными с узлом РИБ, если есть изменения конфигурации, система требует сначала обновить конфигурацию в режиме конфигуратора и только затем можно загрузить данные в режиме Предприятие.
Если узлов РИБ много, тогда эту операцию выполнять вручную очень неудобно и трудоемко, а также есть проблема висящих сеансов, которые препятствуют нормальному обновлению конфигурации.
В данной статье описывается решение, которое автоматизирует указанные задачи.
Ключевой момент: формирование и запуск скриптов в пакетном режиме.
Алгоритм кратко:
1) Регламентное задание проверяет файл обновления, если он есть, тогда запускается соответствующая процедура обновления.
2) Блокируются подключения клиентских сеансов и фоновых заданий.
3) Закрываются все существующие сеансы, за исключением текущего.
4) Выполняется обновление конфигурации.
5) Выполняется загрузка данных.
6) Снимается блокировка клиентских подключений и фоновых заданий.
Функция ОбновлениеКонфигурации() запускается регламентным заданием на стороне подчиненных узлов РИБ при выполнении условий:
Если не ПланыОбмена.ГлавныйУзел()=Неопределено и КонфигурацияИзменена() тогда
ТекстСообщения2 = ТекстСообщения2+ОбновлениеКонфигурации_новый(ЕстьОшибка)+Символы.ПС;
Сообщение = Новый СообщениеПользователю();
Сообщение.Текст = ТекстСообщения2;
Сообщение.Сообщить();
КонецЕсли;
Функция ОбновлениеКонфигурации(ЕстьОшибка) Экспорт
Если ПланыОбмена.ГлавныйУзел()= Неопределено тогда
ВызватьИсключение "Фоновое обновление конфигурации предусмотрено только для узлов РИБ !!";
КонецЕсли;
Попытка
СтрокаСоединения = СтрокаСоединенияИнформационнойБазы ();
Если СтрНачинаетсяС(СтрокаСоединения,"Srvr") тогда
масс1= СтрРазделить(СтрокаСоединения,";",ложь);
массSrvr= СтрРазделить(масс1[0],"=",ложь);
массRef= СтрРазделить(масс1[1],"=",ложь);
Сервер_=массSrvr[1];
База_ =массRef[1];
иначе
ВызватьИсключение "База должна быть серверная !!";
КонецЕсли;
КолСимволовСервер=СтрДлина(Сервер_) ;
КолСимволовБаза=СтрДлина(База_) ;
ИмяСервера= Сред(Сервер_,2,КолСимволовСервер-2); // удаляем лишние кавычки.
ИмяБазы=Сред(База_,2,КолСимволовБаза-2);
ПолныйПуть1С=""""+КаталогПрограммы()+"1cv8.exe"+"""";
ПутьКБазе=""""+ИмяСервера+"\"+ИмяБазы+"""";
АдминБазы = СокрЛП(Константы.Логин.Получить());
ПарольБазы = СокрЛП(Константы.Пароль.Получить());
КодДоступа="123";
Если НЕ ЗначениеЗаполнено(ИмяСервера) ИЛИ НЕ ЗначениеЗаполнено(ИмяБазы) ИЛИ НЕ ЗначениеЗаполнено(ПолныйПуть1С)
ИЛИ НЕ ЗначениеЗаполнено(АдминБазы) ИЛИ НЕ ЗначениеЗаполнено(ПарольБазы) Тогда
Сообщение = Новый СообщениеПользователю();
Сообщение.Текст = "Обновление конфигурации невозможно! Недостаточно параметров для подключения к кластеру!!";
Сообщение.Сообщить();
ВызватьИсключение "Обновление конфигурации невозможно! Недостаточно параметров для подключения к кластеру!!";
КонецЕсли;
СоединениеСАгентом=Неопределено ;
Кластер=Неопределено ;
// ЗаблокироватьСеансы
ЗаблокироватьСеансы (ИмяСервера,ИмяБазы,АдминБазы,ПарольБазы,КодДоступа,СоединениеСАгентом,Кластер);
// ЗАКРЫТЬ сеансы
ЗакрытьСеансы (СоединениеСАгентом,Кластер,ИмяБазы);
КаталогЛогов=Константы.КаталогЛоговДиагностики.Получить();
Если Константы.ЗаписыватьФайлЛогаРИБ.Получить() Тогда
СтрокаЛогирования=" /Out "+ """"+ КаталогЛогов+"updateLog_1C.log"+ """" + " -NoTruncate";
Иначе
СтрокаЛогирования="";
КонецЕсли;
// ЗАПУСТИТЬ строку скрипта
ЗаголовокСтрокиЗапуска= "CMD.exe /c echo ************ %date%_%time% ************>>"+ """"+ КаталогЛогов+"updateLog_1C.log"+ """" ;
// обновление конфы
СтрокаОбновленияКонфигурации =" & TIMEOUT /T 30 /NOBREAK & " +ПолныйПуть1С+" CONFIG /S "+ПутьКБазе+"; /N"+АдминБазы+" /P"+ПарольБазы+" /DisableStartupMessages /DisableStartupDialogs /UpdateDBCfg /UC "
+КодДоступа+СтрокаЛогирования;
// загрузка данных по РИБ
СтрокаЗагрузкиДаныхРИБ = " & TIMEOUT /T 30 /NOBREAK & " + ПолныйПуть1С+ " ENTERPRISE /S "+ПутьКБазе+"; /N"+АдминБазы+" /P"+ПарольБазы+ " /DisableStartupMessages /DisableStartupDialogs /C""ЗагрузитьДанные_РИБ"" /UC "
+КодДоступа+СтрокаЛогирования;
СтрокаЗапуска= ЗаголовокСтрокиЗапуска + СтрокаОбновленияКонфигурации + СтрокаЗагрузкиДаныхРИБ ;
КодЗавершения=ВыполнитьКомандуЧерезШелл (СтрокаЗапуска);
Возврат "Скрипты обновления запущены ...";
Исключение
СнятьБлокировкуПодключений () ;
ЕстьОшибка = Истина;
Возврат ОписаниеОшибки();
КонецПопытки;
КонецФункции
*****************
Функция ВыполнитьКомандуЧерезШелл (СтрокаЗапуска)
WshShell = Новый COMОбъект("WScript.Shell");
КодЗавершения=WshShell.Run(СтрокаЗапуска,0,0);
Возврат КодЗавершения;
КонецФункции
***************
Процедура ПриНачалеРаботыСистемы()
Если СокрЛП(ПараметрЗапуска) = "ЗагрузитьДанные_РИБ" Тогда
МодульОбменаНовый.ВыполнитьЗагрузкуРИБ_ВПакетномРежиме();
МодульОбменаНовый.СнятьБлокировкуПодключений();
ЗавершитьРаботуСистемы(Ложь);
КонецЕсли;
КонецПроцедуры
Процедура ЗаблокироватьСеансы (ИмяСервера,ИмяБазы,АдминБазы,ПарольБазы,КодДоступа,СоединениеСАгентом,Кластер)
НомерТекСеанса= НомерСеансаИнформационнойБазы() ; // Номер текущего Сеанса
DeniedAll = Истина ;
Соединитель = Новый COMОбъект("V83.COMConnector");
СоединениеСАгентом = Соединитель.ConnectAgent(ИмяСервера);
Clusters = СоединениеСАгентом.GetClusters();
для Каждого Кластер из Clusters Цикл
СоединениеСАгентом.Authenticate(Кластер,,); // Authenticate в кластере
WorkingProcesses = СоединениеСАгентом.GetWorkingProcesses(Кластер);
Для каждого Процесс из WorkingProcesses Цикл
РабочПроцесс= Соединитель.ConnectWorkingProcess(Процесс.HostName+":"+СтрЗаменить(Процесс.MainPort, Символы.НПП, ""));
РабочПроцесс.AddAuthentication(АдминБазы,ПарольБазы); // Authenticate в базе
InfoBases = РабочПроцесс.GetInfoBases();
// блокировка подключения
Для каждого InfoBase Из InfoBases Цикл
Если Врег(InfoBase.Name)=ВРЕГ(ИмяБазы) Тогда
InfoBase.ConnectDenied = DeniedAll;
InfoBase.SessionsDenied = DeniedAll;
InfoBase.PermissionCode = КодДоступа;
InfoBase.DeniedMessage = "Обновление конфигурации,база времено недоступна !!";
РабочПроцесс.UpdateInfoBase(InfoBase)
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЦикла;
КонецПроцедуры
Процедура ЗакрытьСеансы (СоединениеСАгентом,Кластер,ИмяБазы)
НомерТекСеанса= НомерСеансаИнформационнойБазы() ; // Номер текущего Сеанса
ЗакрыватьСеансы= Истина;
// закрытие сеансов
Базы=СоединениеСАгентом.GetInfoBases(Кластер);
Для каждого База Из Базы Цикл
Если Врег(База.Name)=ВРЕГ(ИмяБазы) Тогда
Сеансы = СоединениеСАгентом.GetInfoBaseSessions(Кластер,База);
Для Каждого Сеанс из Сеансы Цикл
Если (Сеанс.SessionID = НомерТекСеанса И нРег(Сеанс.AppID) = "backgroundjob" ) ИЛИ нРег(Сеанс.AppID) = "srvrconsole" Тогда
Продолжить;
КонецЕсли;
Если ЗакрыватьСеансы Тогда //TerminateSession
СоединениеСАгентом.TerminateSession(Кластер,Сеанс);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
КонецПроцедуры