Каталог решений - Обмен с помощью WMI

Описание

Читаю здешние темы «обмен через FTP», «через облачный севис», «через почту»… Все эти механизмы имеют кучу недостатков:

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

 — При любой нештатной ситуации (например, не правильный номер сообщения или проблемы с изменением конфигурации) все эти методы требуют ручной обработки события.

— При необходимости внепланового обмена, надо руками лезть во все базы и запускать в них обменные процессы.

— Излишние телодвижения файла выгрузки: из базы во временный каталог, оттуда в письмо (яндекс-диск и пр.), потом во временный каталог приемника и потом загрузка данных в приемник.

 — И т.д.

Использование механизма WMI позволяет исключить все эти неприятности и получить еще кучу плюшек.

У меня есть готовый механизм, но т.к. он интегрирован с другими механизмами общего назначения (резервное копирование, отключение пользователей и т.д.) в отдельную базу, выкладывать его тут не буду, просто опишу принципы.

Я создал отдельную базу, которая (кроме всего прочего), осуществляет обмен РИБ по расписанию регламентного задания.

1. Можно сначала сделать резервную копию (если надо).

2. Проконтролировав выполнение 1 этапа делаем выгрузку центрального узла для всех периферий.

3. Проконтролировав завершение просто копируем файл из временного каталога центрального компьютера на периферийный (при хорошем интернете можно грузить даже непосредственно, но это чревато риском в случае обрыва связи). Контролируем совпадение размеров исходного и полученного файлов. При сбое повторяем установленное количество раз. Не вышло — отмечаем сбой.

4. Загружаем одновременно (последовательно запустив процессы в цикле) периферийные базы.

5. Анализируем лог загрузки и обрабатываем ошибку, если она есть: изменяем номер сообщения или выгружаем, передаем и загружаем конфигурацию центрального узла и т.д. — в зависимости от вида сбоя. Контролируем — не вышло — отмечаем сбой (в дальнейшем «***»).

6. В случае загрузки конфигурации, повторяем загрузку выгрузки центра.

7. Выгружаем периферию. ***

8. Передаем выгрузку периферии в центр. ***

9. Загружаем в центральной узел. ***

Все управление осуществляется одной отдельной базой, которая последовательно запускает распределённые базы в описанном выше порядке, контролирует и фиксирует результаты выполнения.

Для визуализации процесса я использую форму списка справочника. Который содержит в себе список РИБ с необходимыми атрибутами (место выгрузки, путь к исполняемому файлу 1С и пр.), в котором отражается текущая пиктограмма процесса, и лог операций для каждого узла.

Теперь наконец о собственно механизмах WMI.

Запуск удаленной базы:

Locator=Новый COMОбъект(«WbemScripting.SWbemLocator»);

objWMIService=Locator.ConnectServer(КомпIP,»\root\cimv2″, Константы.ЛогинАдминистратора.Получить(),Константы.ПарольАдминистратора.Получить());

Ели база на том же компьютере что и Управляющая БД, то

objWMIService=Locator.ConnectServer(«.»);

objProcess=Ст.objWMIService.Get(«Win32_Process»);

intProcessID=0;              

strCommand= ПутьКИсполняемымФайлам1С+»1cv8.exe ENTERPRISE /S /NZipOut /P»+СокрЛП(Константы.ПарольZip.Получить())+» /DisableStartupMessages  /Out»+ИмяФайлаЛогаВыгрузки;                                       

objProcess.Create(strCommand,null,,intProcessID);

После запуска базы контролируем окончание процесса:

 

pEnum=Ст.objWMIService.ExecQuery("SELECT * FROM Win32_Process WHERE Name = '1cv8.exe'");  

                Для Каждого Object Из pEnum Цикл

                               Про=Object.Properties_;

                               Для Каждого Свойство Из Про Цикл

                                               Если Свойство.Name="ProcessId" Тогда

                                                               Если Свойство.Value=Ст.intProcessID Тогда

                                                                              Если ТекущаяДата()>Ст.Ждать Тогда

                                                                                              Попытка

                                                                                                              Object.Terminate();

                                                                                              Исключение

                                                                                              КонецПопытки;

                                                                                              Ст.Лог=Ст.Лог+"Превышен лимита ожидания операции!"+Символы.ПС;

                                                                                              Ст.Ждать=0;

                                                                                              Возврат Ложь;

                                                                              Иначе

                                                                                              Возврат Истина;

                                                                              КонецЕсли;

                                                               КонецЕсли;

                                                               Прервать;

                                               КонецЕсли;

                               КонецЦикла; 

                КонецЦикла;


В модуль конфигурации РИБ надо добавить процедуры:

 

Процедура ПередНачаломРаботыСистемы(Отказ)

                Если ИмяПользователя()="Zip" Тогда

                               Ждать(5);

                               Если ЗагрузкаОбмена(ПараметрЗапуска) Тогда

                                               ВыгрузкаОбмена(ПараметрЗапуска);                

                               КонецЕсли;       

                               Отказ=Истина;

                ИначеЕсли ИмяПользователя()="ZipOut" Тогда

                               Ждать(5);

                               ВыгрузкаОбмена(ПараметрЗапуска);                

                               Отказ=Истина;

                ИначеЕсли ИмяПользователя()="ZipIn" Тогда

                               Ждать(5);

                               Если ПараметрЗапуска="NodeOff" Тогда

                                               Попытка

                                                               ПланыОбмена.УстановитьГлавныйУзел(Неопределено);

                                                               //Сообщить("Распределение отключено.");

                                               Исключение

                                                               //Сообщить("Распределение уже отключено.");

                                               КонецПопытки;

                               ИначеЕсли ПараметрЗапуска="NodeOn" Тогда

                                               Попытка

                                                               ГлавныйУзел=ПланыОбмена.Филиалы.НайтиПоКоду("000");

                                                               ПланыОбмена.УстановитьГлавныйУзел(ГлавныйУзел);         

                                                               //Сообщить("Распределение включено.");

                                               Исключение

                                                               //Сообщить("Распределение уже включено.");

                                               КонецПопытки;

                               Иначе

                                               ЗагрузкаОбмена(ПараметрЗапуска);

                               КонецЕсли;

                               Отказ=Истина;

                               КонецЕсли;

                КонецЕсли;

КонецПроцедуры

//------------

Процедура ВыгрузкаОбмена(УзелЗВ)

                ФСО=Новый COMОбъект("Scripting.FileSystemObject");

                Попытка

                               ВыборкаУзлов=ПланыОбмена.Филиалы.НайтиПоНаименованию(УзелЗВ); 

                               Узел=ВыборкаУзлов.Ссылка; 

                               ЭтотУзел=ПланыОбмена.Филиалы.ЭтотУзел();

                               Путь=СокрЛП(ЭтотУзел.Место);

                               Если ПланыОбмена.ГлавныйУзел()=Неопределено Тогда

                                               //Путь=СокрЛП(ЭтотУзел.ПутьКБД)+"PC\";

                                               //ПутьП=СокрЛП(ЭтотУзел.ПутьКБД)+"PC\";

                                               

                                               //НФ=НайтиФайлы(ПутьП, СокрЛП(Узел.Код)+"-"+СокрЛП(ЭтотУзел.Код)+".zip");

                                               НФ=НайтиФайлы(Путь, СокрЛП(Узел.Код)+"-"+СокрЛП(ЭтотУзел.Код)+".zip");

                                               Попытка

                                                               ФайлЗ=НФ[0].ПолноеИмя;

                                                               ФСО.DeleteFile(ФайлЗ);

                                               Исключение

                                                               Возврат;

                                               КонецПопытки;

                               //Иначе

                               //            Путь=СокрЛП(ЭтотУзел.ПутьКБД)+"PC\";

                               //            ПутьП=СокрЛП(ЭтотУзел.ПутьКБД)+"CP\";

                               КонецЕсли;

                               

                               ИмяФайлаСообщения=Путь+"Выгрузка.xml"; 

                               ЗаписьXML=Новый ЗаписьXML(); 

                               ЗаписьXML.ОткрытьФайл(ИмяФайлаСообщения); 

                               ЗаписьСообщения=ПланыОбмена.СоздатьЗаписьСообщения(); 

                               ЗаписьСообщения.НачатьЗапись(ЗаписьXML,Узел); 

                                ПланыОбмена.ЗаписатьИзменения(ЗаписьСообщения,Константы.ТранзакцииОбмена.Получить()); 

                               ЗаписьСообщения.ЗакончитьЗапись(); 

                               ЗаписьXML.Закрыть(); 

                               ЗФ=Новый ЗаписьZipФайла(Путь+СокрЛП(ЭтотУзел.Код)+"-"+СокрЛП(Узел.Код)+".zip"); 

                               ЗФ.Добавить(ИмяФайлаСообщения);

                               ЗФ.Записать();

                               Сообщить("Выгружены данные ("+ЭтотУзел+" - "+УзелЗВ+") -  "+ТекущаяДата());

                Исключение

                               ОО=ОписаниеОшибки();

                               ЗаписьЖурналаРегистрации("ОБМЕН.Выгрузка ("+ЭтотУзел+" - "+УзелЗВ+")", УровеньЖурналаРегистрации.Ошибка, , , ОО);

                               Сообщить(">>> ВЫГРУЗКА("+ЭтотУзел+" - "+УзелЗВ+"): "+ОО);

                КонецПопытки;

                Попытка

                               ФСО.DeleteFile(Путь+"Выгрузка.xml");

                Исключение

                КонецПопытки;

КонецПроцедуры

//------------

Функция ЗагрузкаОбмена(УзелЗВ)

                Первый=Истина;

                ЭтотУзел=ПланыОбмена.Филиалы.ЭтотУзел();

~АА:      

                Попытка

                               Если Первый Тогда

                                               ФСО=Новый COMОбъект("Scripting.FileSystemObject");

                                               Попытка

                                                               ФСО.DeleteFile(СокрЛП(ЭтотУзел.Место)+"New.txt");

                                               Исключение

                                               КонецПопытки;

                                               ВыборкаУзлов=ПланыОбмена.Филиалы.НайтиПоНаименованию(УзелЗВ); 

                                               Узел=ВыборкаУзлов.Ссылка; 

                                               Путь=СокрЛП(ЭтотУзел.Место);

                                               //Если ПланыОбмена.ГлавныйУзел()=Неопределено Тогда

                                               //                           Путь=СокрЛП(ЭтотУзел.ПутьКБД)+"PC\";

                                               //            Иначе

                                               //                           Путь=СокрЛП(ЭтотУзел.ПутьКБД)+"CP\";

                               //            КонецЕсли;

                                               НФ=НайтиФайлы(Путь, СокрЛП(Узел.Код)+"-"+СокрЛП(ЭтотУзел.Код)+".zip");

                                               Попытка

                                                              ФайлЗ=НФ[0].ПолноеИмя;

                                               Исключение

                                                               Возврат Ложь;

                                               КонецПопытки;

                                               ЗФ=Новый ЧтениеZipФайла(ФайлЗ); 

                                               ЗФ.ИзвлечьВсе(Путь);

                                               ИмяФайлаСообщения=Путь+"Выгрузка.xml";

                               КонецЕсли;

                               ЧтениеXML=Новый ЧтениеXML(); 

                               ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения); 

                               ЧтениеСообщения=ПланыОбмена.СоздатьЧтениеСообщения(); 

                               ЧтениеСообщения.НачатьЧтение(ЧтениеXML); 

                               Попытка

                                               ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения,Константы.ТранзакцииОбмена.Получить()); 

                                               

                                               Об=Узел.ПолучитьОбъект();

                                               Об.ДатаОбмена=ТекущаяДата();

                                               Об.Записать();

                               Исключение

                                               ОО=ОписаниеОшибки();

                                               ЧтениеXML.Закрыть(); 

                                               ФСО.DeleteFile(Путь+"Выгрузка.xml");

                                               Если ПланыОбмена.ГлавныйУзел()<>Неопределено Тогда

                                                               ФСО.DeleteFile(ФайлЗ);

                                               КонецЕсли;

                                               Если Найти(Строка(ОО),"изменения конфигурации")>0 Тогда

                                                               Если КонтрольПериферии() Тогда

                                                                              ФСО.CreateTextFile(СокрЛП(ЭтотУзел.Место)+"New.txt");

                                                                              Сообщить("Загружена конфигурация ("+УзелЗВ+" - "+ЭтотУзел+") -  "+ТекущаяДата());

                                                               КонецЕсли;

                                                               Сообщить(">>> ЗАГРУЗКА ("+УзелЗВ+" - "+ЭтотУзел+"): "+ОО);

                                                               Возврат Истина;

                                               Иначе  

                                                               ЗаписьЖурналаРегистрации("ОБМЕН.Загрузка ("+УзелЗВ+" - "+ЭтотУзел+")",                УровеньЖурналаРегистрации.Ошибка, , , ОО);

                                                               Сообщить(">>> ЗАГРУЗКА ("+УзелЗВ+" - "+ЭтотУзел+"): "+ОО);

                                                               Возврат Ложь;

                                               КонецЕсли;

                               КонецПопытки;

                               ЧтениеСообщения.ЗакончитьЧтение(); 

                               ЧтениеXML.Закрыть(); 

                               ФСО.DeleteFile(Путь+"Выгрузка.xml");

                               Если ПланыОбмена.ГлавныйУзел()<>Неопределено Тогда

                                               ФСО.DeleteFile(ФайлЗ);

                               КонецЕсли;

                               Сообщить("Загружены данные ("+УзелЗВ+" - "+ЭтотУзел+") -  "+ТекущаяДата());

                               Возврат Истина;

                Исключение

                               ОО=ОписаниеОшибки();

                               //=========

                               Если Найти(Строка(ОО),"Номер сообщения меньше или равен")>0 Тогда

                                               Об=Узел.ПолучитьОбъект();

                                               Об.НомерПринятого=Об.НомерПринятого-1;

                                               Об.Записать();

                                               Первый=Ложь;

                                               Перейти ~АА;  

                               КонецЕсли;

                               //=========

                               Попытка

                                               ФСО.DeleteFile(Путь+"Выгрузка.xml");

                               Исключение

                               КонецПопытки;

                               Попытка

                                               Если ПланыОбмена.ГлавныйУзел()<>Неопределено Тогда

                                                               ФСО.DeleteFile(ФайлЗ);

                                               КонецЕсли;

                               Исключение

                               КонецПопытки;

                               ЗаписьЖурналаРегистрации("ОБМЕН.Загрузка", УровеньЖурналаРегистрации.Ошибка, , , ОО);

                               Сообщить(">>> ЗАГРУЗКА("+УзелЗВ+"): "+ОО);

                               Возврат Ложь;

                КонецПопытки;

КонецФункции

 //------------

Процедура Ждать(СекЖ)

                Врем=ТекущаяДата()+СекЖ;

                КК=1;

                Пока Врем>=ТекущаяДата() Цикл

                               Предупреждение("Ждем: "+КК, 1, "Задержка...");    

                               КК=КК+1;            

                КонецЦикла;

КонецПроцедуры         

//-------------

Функция ПолучитьСервер(Стр) Экспорт

                Пром=СтрЗаменить(Стр,"\\","");

                Пром=СтрЗаменить(Пром,":","");

                Поз=Найти(Пром,"\");

                Если Поз=0 Тогда

                               Возврат Неопределено;

                Иначе

                               Возврат Лев(Пром,Поз-1);

                КонецЕсли;

КонецФункции             

  

 

Если обмен осуществляется между базами с конфигурацией на поддержке, то весь этот механизм можно оформить через запуск соответствующих внешних обработок из командной строки.

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

Резюме: с помощью WMI можно управлять всем процессом обмена из одного места, имея перед собой полную картину происходящего (если не ленится оформить соответствующую визуализацию) и возможность прервать процесс или осуществить ручной запуск обменной цепочки.

 

has been added to your cart:
Оформление заказа