gifts2017

РИБ на v 8: Автоматический прием сообщения обмена, содержащего изменения в конфигурации

Опубликовал Андрей Скляров (coder1cv8) в раздел Администрирование - Распределенная БД (УРИБ, УРБД)

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

Для выполнения обновления конфигурации информационной базы, необходимым условием является монопольный режим, т.е. отсутствие в базе других активных пользователей. Таким образом, предварительно необходимо «выгнать» из базы работающих пользователей. В типовых конфигурациях это можно сделать, установив константу РежимЗавершенияРаботыПользователей. Исходя из этого, наша процедура обновления конфигурации выглядит следующим образом:
Процедура
ОбновитьКонфигурацию
()
ОтключитьОбработчикОжидания
("АвтообменДанными")
;  
// отключим наш обработчик, в котором происходит обмен сообщениями
Константы
.
РежимЗавершенияРаботыПользователей
.
Установить
(
Перечисления
.
РежимыЗавершенияРаботыПользователей
.
ЗавершитьПослеОжиданияПодтвержденияПользователя
)
;
	ПодключитьОбработчикОжидания
("ОбновлениеКонфигурацииИБ",10)
;
КонецПроцедуры
Обработчик ожидания ОбновлениеКонфигурацииИБ, предназначен для того, что бы с установленным интервалом (в данном случае 10 сек.), проверять вышли ли все пользователи из базы и если да, то запускать обновление конфигурации информационной базы. Само обновление конфигурации реализовано с помощью внешнего скрипта. Ниже приведен программный код этого обработчика:
Процедура
ОбновлениеКонфигурацииИБ
() Экспорт
МассивСоединений
=
ПолучитьСоединенияИнформационнойБазы
()
;
	
Если
МассивСоединений
.
Количество
()>1 Тогда Возврат
;  
// ждем дальше... КонецЕсли
;
   	СтрокаСоединения
=
СтрокаСоединенияИнформационнойБазы
()
;
 	ПутьКСкрипту
=
КаталогВременныхФайлов
()+"exchange.vbs"
;
   	Скрипт
=
Новый ЗаписьТекста
(
ПутьКСкрипту
,
КодировкаТекста
.
ANSI
)
;
   	Скрипт
.
ЗаписатьСтроку
("WScript.Sleep 5000")
; 
// на всякий случай
Скрипт
.
ЗаписатьСтроку
("Set WshShell=CreateObject(""WScript.Shell"")")
;
   	Команда
=""""""+
КаталогПрограммы
()+"1CV8.EXE"""" CONFIG"+
?
(
НСтр
(
СтрокаСоединения
,"File")<>""," /F "+
НСтр
(
СтрокаСоединения
,"File")," /S "+
НСтр
(
СтрокаСоединения
,"Srvr")+"\"+
НСтр
(
СтрокаСоединения
,"Ref"))+" /N Exchange /P Exchange /UpdateDBCfg"
;
   	Скрипт
.
ЗаписатьСтроку
("ReturnCode=WshShell.Run("""+
Команда
+""",1,1)")
;
   	Скрипт
.
ЗаписатьСтроку
("If ReturnCode=0 Then")
; 
// если обновились удачно, то пытаемся дочитать сообщение
Команда
=""""""+
КаталогПрограммы
()+"1CV8.EXE"""" ENTERPRISE"+
?
(
НСтр
(
СтрокаСоединения
,"File")<>""," /F "+
НСтр
(
СтрокаСоединения
,"File")," /S "+
НСтр
(
СтрокаСоединения
,"Srvr")+"\"+
НСтр
(
СтрокаСоединения
,"Ref"))+" /N Exchange /P Exchange"
;
   	Скрипт
.
ЗаписатьСтроку
("WshShell.Run """+
Команда
+""",1,0")
;
   	Скрипт
.
ЗаписатьСтроку
("End If")
;
   	Скрипт
.
ЗаписатьСтроку
("Set FSO=CreateObject(""Scripting.FileSystemObject"")")
;
   	Скрипт
.
ЗаписатьСтроку
("Set File=FSO.GetFile(WScript.ScriptFullName)")
;
   	Скрипт
.
ЗаписатьСтроку
("File.Delete")
;
   	Скрипт
.
Закрыть
()
;
   	ЗапуститьПриложение
(
ПутьКСкрипту
)
;
   	ЗавершитьРаботуСистемы
(
Ложь
)
;
КонецПроцедуры
Сформированный в результате скрипт, запускает обновление конфигурации базы данных, затем базу в режиме Предприятия и после этого сам себя удаляет. Подразумевается, что при старте системы, происходит подключение обработчика ожидания, в котором выполняется авто обмен данными с установленной частотой. Так же, важно не забывать при этом «выключать» РежимЗавершенияРаботыПользователей. Ниже приведен пример реализации подключения авто обмена:
Процедура
ПриНачалеРаботыСистемы
() // Инициализация авто обмена Если
РольДоступна
("АвтоОбмен") Тогда // Если нами был включен запрет для обновления конфигурации ИБ Если
Константы
.
РежимЗавершенияРаботыПользователей
.
Получить
()<>
Перечисления
.
РежимыЗавершенияРаботыПользователей
.
РазрешитьРаботу 
Тогда
Константы
.
РежимЗавершенияРаботыПользователей
.
Установить
(
Перечисления
.
РежимыЗавершенияРаботыПользователей
.
РазрешитьРаботу
)
;
		
КонецЕсли
;
		ЧастотаОбмена
=
Константы
.
ЧастотаАвтоОбменаДанными
.
Получить
()
;
		
Если
ЧастотаОбмена
<>0 Тогда
ПодключитьОбработчикОжидания
("АвтообменДанными",
ЧастотаОбмена
)
;
		
Иначе
Сообщить
("Не задана частота авто обмена, подключение не возможно.",
СтатусСообщения
.
Внимание
)
;
		
КонецЕсли
;
	
КонецЕсли
;
КонецПроцедуры

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Аркадий Кучер (Abadonna) 25.07.07 18:50
Хоть и не программлю в 8-ке, подозреваю, что статья хорошая и полезная
+1
2. Андрей Скляров (coder1cv8) 25.07.07 20:34
(1) Спасибо, а то я уже не знаю как относиться к тому, что никто ни как не прокомментировал... )
ALL: Если статья плохая, то так и говорим не стесняемся... )
3. Сергей Старых (tormozit) 03.08.07 10:35
Хорошая статья. У нас сделано похожим образом, но еще добавлена попытка динамического обновления и рассылки сообщений пользователям.
4. Сергей Старых (tormozit) 03.08.07 10:56
Кстати, а поясни пожалуйста
Код
НСтр(СтрокаСоединения,"File")
Показать полностью
5. Андрей Скляров (coder1cv8) 06.08.07 09:31
(4) Как говорит Синтакс-помощник, НСтр - "получает строку на языке текущего пользователя или указанном языке из набора строк на разных языках конфигурации". А СтрокаСоединения - это как мы видим СтрокаСоединенияИнформационнойБазы(), которая представляет собой, вобщем-то, подобие набора строк на разных языках. Т.е., если для НСтр в качестве параметра <Код языка>, передать "File", то мы получим каталог информационной базы, для файлового режима. Для клиент-серверного режима, аналогично можно получить значения "Srvr" и "Ref" из строки соединения.
6. Сергей Старых (tormozit) 06.08.07 09:38
Понял. Спасибо, берем на вооружение.
7. Илья Никифоров (ILNIK) 25.06.08 17:50
хотелось бы ,что бы проверялось на попытку динамического обновления и если возможно, обновляла бы динамически
8. Андрей Скляров (coder1cv8) 25.06.08 19:14
(7) Ну это давно писалось, я тогда 8.1 ещё не видел... )
9. Артур Аюханов (artbear) 12.02.09 09:48
Вариант с динамическим обновлением еще не появился?
10. Андрей Скляров (coder1cv8) 12.02.09 11:38
(9) Нет. Сейчас эта тема для меня не актуальна, да и времени свободного совсем нет... (
11. Александр Гранин (stack_g) 16.02.09 15:02
Спасибо, то что нужно. Сейчас по этому примеру буду прописывать :)
12. NOX85 27.03.09 17:00
Отличная вещь. Только возникла одна проблема, может кто подскажет как ее решить. Я немного доработал эту обработку и установил ее в качестве регламентного задания, т. е. когда в узел приходи письмо с обновлением, он в фоновом режиме выгоняет всех пользователей (Через сервер 1С). После чего обновляется. Вот только проблема в том что первый раз она обновляется нормально, а второй, в сервере 1С зависате, фоновое задание, и не как его удалить нельзя, даже если в SQL разорвать соединение, в сервере 1С оно всеравно висит, и соответственно обновление больше не делается, помогает только перезапуск службы "Агент сервер 1С".
13. Николай Бойко (Niko_) 04.06.09 17:21
У меня серверный вариант,через регламентное задание выполняется динамическое задание,токо в задании прописал просто обмен, а при чтении сообщения вставил скрипт и всё ОК!
Только теперь надо сделать предупреждение пользователям, подождать определенное время, и перезапустить (обновить) конфу. Может кто чё подскажет?
14. gulchitai (gulchitai) 06.10.09 05:38
Статья очень хорошая, огромное спасибо автору. Внедрила это у нас. только ЗавершитьРаботуСистемы(Ложь) в процедуре обновления иб упорно не срабатывало (не закрывало 1с). зато ПрекратитьРаботуСистемы() сработало отлично.
И еще не запускается, если имя БД с пробелами, тогда надо еще путь к базе с кавычками указывать, даже если серверный вариант.
15. gulchitai (gulchitai) 06.10.09 05:41
Статья хорошая, огромное спасибо автору.
Только ЗавершитьРаботуСистемы(Ложь) упорно не работает у меня, не закрывает 1с. Заменила на ПрекратитьРаботуСистемы и все пошло. И еще, если имя БД с пробелами, то не работает. нужны дополнительные кавычки в серверном варианте.
coder1cv8; +1 Ответить
17. Павел Цыбин (Advakant) 15.02.10 13:47
извеняюсь за нубо вопрос...ну куда этот код вписывается ?
18. Павел Цыбин (Advakant) 15.02.10 13:49
Попытка
ЧтениеXML=Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения);
ЧтениеСообщения=ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения);
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
Исключение
СтрОписания="Обновление может быть выполнено в режиме Конфигуратор.";
Если Прав(ОписаниеОшибки(),СтрДлина(СтрОписания))=СтрОписания Тогда
ОбновитьКонфигурацию(); // процедура обновления конфигурации
Иначе
Сообщить(ОписаниеОшибки());
КонецЕсли;
КонецПопытки;
19. Андрей Скляров (coder1cv8) 15.02.10 17:53
(18) В свою обработку читающую сообщения )
Вообще, с тех пор как я это писал, прошло много времени... Сейчас уже подобный механизм встроен в типовые, можно там подсмотреть...
20. Артем Титеев (a_titeev) 14.03.10 18:45
Кто использует подобный механизм, может пригодится вывод сообщения о том, что в данный момент производится обновление... процесс обновления может быть затянутым, вывод сообщения пользователю не помешает, т.к. сталкивался с тем, что если, например, делается длительная реструктуризация пользак может например тупо выключить комп и пойти домой... А утром приходит - не запускается... И давай названивать... А база уже убита...

Применительно тому коду, который есть здесь, можно сделать хотя бы так (во всяком случае делал, изменив код формирования скрипта):

...
    // создаем скрипт с сообщением
    ПутьКСкрипту1=КаталогВременныхФайлов()+"message.vbs";
    Скрипт=Новый ЗаписьТекста(ПутьКСкрипту1,КодировкаТекста.ANSI);
    Скрипт.ЗаписатьСтроку("MsgBox ""Производится обновление конфигурации... Не выключайте компьютер!"",, ""Внимание!""");
    Скрипт.Закрыть();
    // создаем основной скрипт
    СтрокаСоединения=СтрокаСоединенияИнформационнойБазы();
    ПутьКСкрипту2=КаталогВременныхФайлов()+"exchange.vbs";
    Скрипт=Новый ЗаписьТекста(ПутьКСкрипту2,КодировкаТекста.ANSI);
    Скрипт.ЗаписатьСтроку("Dim WshShell, oExec");
    Скрипт.ЗаписатьСтроку("Set WshShell=CreateObject(""WScript.Shell"")");
    Скрипт.ЗаписатьСтроку("Set oExec = WshShell.Exec(""wscript.exe """""+ПутьКСкрипту1+""""""")");
    Скрипт.ЗаписатьСтроку("WScript.Sleep 5000"); // на всякий случай
    Команда=""""""+КаталогПрограммы()+"1CV8.EXE"""" CONFIG "+?(НСтр(СтрокаСоединения,"File")<>""," /F """""+НСтр(СтрокаСоединения,"File")," /S """""+НСтр(СтрокаСоединения,"Srvr")+"\"+НСтр(СтрокаСоединения,"Ref"))+""""" /N Exchange /P Exchange /UpdateDBCfg";
    Скрипт.ЗаписатьСтроку("ReturnCode=WshShell.Run("""+Команда+""",1,1)");
    Скрипт.ЗаписатьСтроку("If ReturnCode=0 Then"); // если обновились удачно, то пытаемся дочитать сообщение
    Команда=""""""+КаталогПрограммы()+"1CV8.EXE"""" ENTERPRISE"+?(НСтр(СтрокаСоединения,"File")<>""," /F """""+НСтр(СтрокаСоединения,"File")," /S """""+НСтр(СтрокаСоединения,"Srvr")+"\"+НСтр(СтрокаСоединения,"Ref"))+""""" /N " + ИмяПользователя();
    Скрипт.ЗаписатьСтроку("WshShell.Run """+Команда+""",1,0");
    Скрипт.ЗаписатьСтроку("End If");
    Скрипт.ЗаписатьСтроку("Set FSO=CreateObject(""Scripting.FileSystemObject"")");
    Скрипт.ЗаписатьСтроку("Set File=FSO.GetFile(WScript.ScriptFullName)");
    Скрипт.ЗаписатьСтроку("oExec.Terminate");
    Скрипт.ЗаписатьСтроку("File.Delete");
    Скрипт.Закрыть();
    ЗапуститьПриложение(ПутьКСкрипту2);
...
...Показать Скрыть



PS. Механизм в типовых довольно убогий. Подобный все равно лучше, во всяком случае, когда не применяется автоматический обмен, а обмениваемся "вручную"... Только нужно код немного поменять из примера...
adhocprog; borman; +2 Ответить
21. Алексей Козаченко (borman) 23.11.11 15:56
Типовой механизм убогий однозначно, ИМХО.
Автору спасибо!
22. sat.m.n@mail.ru Сукачов (bolush) 12.03.12 15:02
Этот то что я искал, я думаю что поможет, спасибо автору:)
23. Дмитрий Леонов (Psylocibine) 15.06.12 13:18
Спасибо, буду ковырять под себя)
24. Александр Крынецкий (echo77) 28.09.14 11:53
Переоформите листинги программ в публикации - читать невозможно
25. Rustem Galin (rustemg) 21.03.15 16:42
Вот сформатированный:

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

При чтении сообщения, определить, что получены изменения конфигурации.
Выполнить обновление конфигурации базы данных.
"Дочитать" сообщение обмена.

Что бы определить факт получения изменений в метаданных можно воспользоваться методом глобального контекста КонфигурацияИзменена() или, выполняя чтение сообщения обмена в конструкции Попытка, проанализировать ОписаниеОшибки(). Например:

Попытка
ЧтениеXML=Новый ЧтениеXML;
ЧтениеXML.ОткрытьФайл(ИмяФайлаСообщения);
ЧтениеСообщения=ПланыОбмена.СоздатьЧтениеСообщения();
ЧтениеСообщения.НачатьЧтение(ЧтениеXML);
ПланыОбмена.ПрочитатьИзменения(ЧтениеСообщения);
ЧтениеСообщения.ЗакончитьЧтение();
ЧтениеXML.Закрыть();
Исключение
СтрОписания="Обновление может быть выполнено в режиме Конфигуратор.";
Если Прав(ОписаниеОшибки(),СтрДлина(СтрОписания))=СтрОписания Тогда
ОбновитьКонфигурацию(); // процедура обновления конфигурации
Иначе
Сообщить(ОписаниеОшибки());
КонецЕсли;
КонецПопытки;



Для выполнения обновления конфигурации информационной базы, необходимым условием является монопольный режим, т.е. отсутствие в базе других активных пользователей. Таким образом, предварительно необходимо «выгнать» из базы работающих пользователей. В типовых конфигурациях это можно сделать, установив константу РежимЗавершенияРаботыПользователей. Исходя из этого, наша процедура обновления конфигурации выглядит следующим образом:

Процедура ОбновитьКонфигурацию()
ОтключитьОбработчикОжидания("АвтообменДанными"); // отключим наш обработчик, в котором происходит обмен сообщениями
Константы.РежимЗавершенияРаботыПользователей.Установить(Перечисления.РежимыЗавершенияРаботыПользователей. ЗавершитьПослеОжиданияПодтвержденияПользователя);
ПодключитьОбработчикОжидания("ОбновлениеКонфигурацииИБ",10);
КонецПроцедуры



Обработчик ожидания "ОбновлениеКонфигурацииИБ", предназначен для того, что бы с установленным интервалом (в данном случае 10 сек.), проверять вышли ли все пользователи из базы и если да, то запускать обновление конфигурации информационной базы. Само обновление конфигурации реализовано с помощью внешнего скрипта. Ниже приведен программный код этого обработчика:

Процедура ОбновлениеКонфигурацииИБ() Экспорт
МассивСоединений=ПолучитьСоединенияИнформационнойБазы();
Если МассивСоединений.Количество()>1 Тогда
Возврат; // ждем дальше...
КонецЕсли;
СтрокаСоединения=СтрокаСоединенияИнформационнойБазы();
ПутьКСкрипту=КаталогВременныхФайлов()+"exchange.vbs";
Скрипт=Новый ЗаписьТекста(ПутьКСкрипту,КодировкаТекста.ANSI);
Скрипт.ЗаписатьСтроку("WScript.Sleep 5000"); // на всякий случай
Скрипт.ЗаписатьСтроку("Set WshShell=CreateObject(""WScript.Shell"")");
Команда=""""""+КаталогПрограммы()+"1CV8.EXE"""" CONFIG"+?(НСтр(СтрокаСоединения,"File")<>""," /F "+НСтр(СтрокаСоединения,"File")," /S "+НСтр(СтрокаСоединения,"Srvr")+"\"+НСтр(СтрокаСоединения,"Ref"))+" /N Exchange /P Exchange /UpdateDBCfg";
Скрипт.ЗаписатьСтроку("ReturnCode=WshShell.Run("""+Команда+""",1,1)");
Скрипт.ЗаписатьСтроку("If ReturnCode=0 Then"); // если обновились удачно, то пытаемся дочитать сообщение
Команда=""""""+КаталогПрограммы()+"1CV8.EXE"""" ENTERPRISE"+?(НСтр(СтрокаСоединения,"File")<>""," /F "+НСтр(СтрокаСоединения,"File")," /S "+НСтр(СтрокаСоединения,"Srvr")+"\"+НСтр(СтрокаСоединения,"Ref"))+" /N Exchange /P Exchange";
Скрипт.ЗаписатьСтроку("WshShell.Run """+Команда+""",1,0");
Скрипт.ЗаписатьСтроку("End If");
Скрипт.ЗаписатьСтроку("Set FSO=CreateObject(""Scripting.FileSystemObject"")");
Скрипт.ЗаписатьСтроку("Set File=FSO.GetFile(WScript.ScriptFullName)");
Скрипт.ЗаписатьСтроку("File.Delete");
Скрипт.Закрыть();
ЗапуститьПриложение(ПутьКСкрипту);
ЗавершитьРаботуСистемы(Ложь);
КонецПроцедуры



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

Процедура ПриНачалеРаботыСистемы()
// Инициализация авто обмена
Если РольДоступна("АвтоОбмен") Тогда
// Если нами был включен запрет для обновления конфигурации ИБ
Если Константы.РежимЗавершенияРаботыПользователей.Получить()<>Перечисления.РежимыЗавершенияРаботыПользователей.РазрешитьРаботу Тогда
Константы.РежимЗавершенияРаботыПользователей.Установить(Перечисления.РежимыЗавершенияРаботыПользователей.РазрешитьРаботу);
КонецЕсли;
ЧастотаОбмена=Константы.ЧастотаАвтоОбменаДанными.Получить();
Если ЧастотаОбмена<>0 Тогда
ПодключитьОбработчикОжидания("АвтообменДанными",ЧастотаОбмена);
Иначе
Сообщить("Не задана частота авто обмена, подключение не возможно.",СтатусСообщения.Внимание);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа