Первым делом настроили РБД таким образом, что в регионах остались подчиненные узлы, а в едином центре - главные (делалось это конечно не только ради обновления - иначе можно было бы попробовать и другие варианты, без УРБД). Главные узлы подключили к единому хранилищу. Однако обновлять десять баз, даже при наличии хранилища - занятие довольно "муторное". Поднимаем вопрос пакетного режима конфигуратора:
REM ------------- Обновление базы из хранилища (cmd) ----------------------- set bin = "C:\Program Files (x86)\1cv8\8.3.9.2170\bin\1cv8.exe" set Srvr = srv set Base = infobase set Name = Admin set Pass = pass set Repo = tcp://srv/conf set Code = GoD set Log = D:\auto\logs\log_%date:~0,2%%date:~3,2%%date:~6,4%.txt %bin% DESIGNER /S"%Srvr%/%Base%" /N%Name% /P%Pass% /ConfigurationRepositoryF%Repo% /ConfigurationRepositoryN%Base% /ConfigurationRepositoryUpdateCfg /UC%Code% /OUT%Log% -NoTruncate REM ---------------- Обновление базы данных (cmd) -------------------------- set bin = "C:\Program Files (x86)\1cv8\8.3.9.2170\bin\1cv8.exe" set Srvr = srv set Base = infobase set Name = Admin set Pass = pass set Code = GoD set Log = D:\auto\logs\log_%date:~0,2%%date:~3,2%%date:~6,4%.txt %bin% DESIGNER /S"%Srvr%/%Base%" /N%Name% /P%Pass% /UpdateDBCfg -Server /UC%Code% /OUT%Log% -NoTruncate
Уже неплохо! Написать bat/cmd файлик, который сделает это для десятка баз - не составляет труда... Если бы не одно "но" - все это нужно делать в "монопольном" режиме, т.е. когда в системе/системах нет пользователей. Как выгонять пользователей из клиент-серверной 1С? Скриптом! vbs, например:
'----------------------- Закрыть все соединения с конкретной базой (vbs) --------------------------- Set ComConnector = CreateObject("v83.ComConnector")'это, по сути, консоль кластера Set ServerAgent = ComConnector.ConnectAgent("srv")' вернее вот это Clasters = ServerAgent.GetClusters() For Each Claster In Clasters ServerAgent.Authenticate Claster, ClasterAdminName, ClasterAdminPass 'Как не странно неинициализированные значения прокатывают, если на кластере нет авторизации Sessions = ServerAgent.GetSessions(Claster) For Each Session In Sessions If Session.InfoBase.Name = "infobase" Then Call ServerAgent.TerminateSession(Claster,Session) End If Next Exit For Next '----------------------- Запретить соединения с конкретной базой (vbs) ----------------------------- Set ComConnector = CreateObject("v83.ComConnector") Set ServerAgent = ComConnector.ConnectAgent("srv") Clasters = ServerAgent.GetClusters() For Each Claster In Clasters ServerAgent.Authenticate Claster, ClasterAdminName, ClasterAdminPass WorkingProcesses = ServerAgent.GetWorkingProcesses(Claster) For Each WorkingProcess In WorkingProcesses 'чуток сложнее, нужно подключение к рабочему процессу... If WorkingProcess.Running = 1 Then Set connecttoworkprocess = ComConnector.ConnectWorkingProcess("tcp://" + WorkingProcess.HostName + ":" + CStr(WorkingProcess.MainPort)) connecttoworkprocess.AddAuthentication "Admin", "pass" 'а здесь уже нужны реальные логин/пароль к конкретной базе InfoBases = connecttoworkprocess.GetInfoBases() For Each InfoBase In InfoBases If InfoBase.Name = "infobase" Then InfoBase.ConnectDenied = True InfoBase.DeniedFrom = CStr(Now()) InfoBase.DeniedTo = CStr(Now() + 1 / 24 * 3) InfoBase.DeniedMessage = "База заблокированна администратором!" InfoBase.PermissionCode = "GoD" connecttoworkprocess.UpdateInfoBase (InfoBase) Exit For End If Next Exit For End If Next Exit For Next
Ну, т.е. мы сначала запрещаем соединения с базой (не забыв при этом установить код разрешения), потом обрываем существующие сессии пользователей, потом обновляем конфигурацию из хранилища и конфигурацию базы данных (указывая установленный ранее код разрешения)... Разрешить работу с базами после этого не сложнее, чем запретить, просто в строке InfoBase.ConnectDenied = True меняем на False (и при желании очищаем остальные поля).
Все это хорошо, но у нас базы распределенные. В принципе изменения в удаленные базы уйдут с ближайшим обменом по расписанию, но мы можем сделать это и принудительно, причем способов у нас несколько (речь идет об относительно типовой конфигурации, где присутствуют стандартные настройки УРБД):
- Настроить автоматический обмен по событию - при входе определенного пользователя в систему. Тогда нам просто достаточно запустить 1С под этим пользователем.
- Можем использовать параметр командной строки /Execute для запуска обработки в которой может быть прописано что угодно, включая вызов экспортной процедуры общего модуля для запуска обмена.
- Или можем использовать vbs скрипт в тех же целях:
'------------------- Выполнить экспортную процедуру общего модуля (vbs) ------------------------------ Set Base = CreateObject("V83.Application") Base.Connect("Srvr='srv';Ref='infobase';Usr=Admin;Pwd=pass;UC=GoD")'Стандартная строка соединения 1С Base.[МодульРегламентныхЗаданий].[ВыполнитьОбменДаннымиДляНастройкиАвтоматическогоОбменаДанными]("000001") 'Для того, что бы свободно использовать кириллицу, нужны квадратные скобки
Продолжим... В принципе для автоматического обновления ночью приведенной информации достаточно: нужно просто настроить автоматические задания на головном и региональных серверах с запасом по времени на обмен. Ну т.е. мы сначала проводим все эти действия на стороне головного сервера, а потом запускаем все тоже самое в обратном порядке (сначала обмен, потом выгоняем пользователей и обновляем базу) в регионе. Но в нашем случае есть ряд нюансов, а именно:
- Нестабильные каналы и разные часовые пояса превращают расчет этого самого "запаса" в непростой квест.
- Базы а регионе далеко не всегда работают в клиент-серверном режиме, есть и файловые. А значит, выгнать пользователей этим скриптом не получится.
- Хотелось бы иметь инструмент, позволяющий запустить принудительное обновление, не в конкретно заданное время, а в любой момент, т.е. процедуры "здесь" и "там" должны быть связаны (выполнятся последовательно).
Зато имеются и положительные моменты (я же рассказываю о собственном конкретном опыте, а не об универсальном решении):
- удаленные сервера доступны внутри единой сети;
- пользователи удаленных площадок работают на терминалах, т.е. клиенты 1С запущены не на рабочих станциях, а на одном конкретном сервере.
Первое позволяет использовать программку psexec для удаленного запуска команды на нужном сервере, а второе радикально решить проблему завершения сеансов с помощью taskkill. Первую нужно скачать, вторая доступна из командной строки по умолчанию.
Вообще типовые конфигурации 1С предоставляют условно "штатный" механизм завершения работы пользователей, который по задумке должен одинаково отрабатывать и в файловом и в клиент-серверном варианте работы (для установки нужно зайти в базу с параметром /CЗавершитьРаботуПользователей, для снятия /CРазрешитьРаботуПользователей). однако на деле мне показался этот метод не очень стабильным, а главное "тяжеловесным" (запускать целое приложение ради сравнительно элементарных действий не хочется) и долгим (по факту 1С запускает обработчик ожидания, который пытается завершить сенсы, пока это у него в конце концов не получится). Вариант с vbs, описанный выше, неплохо зарекомендовал себя на клиент-серверных базах, но он не применим в файловом режиме ( нету объекта v83.ComConnector). Для файлового же режима пара "лайфхаков":
- Заблокированна база или нет по факту определяется наличием либо отсутствием файлика 1Cv8.cdn в каталоге базы данных. Да, вот так все просто. :) Содержимое файлика:
{1,00010101000000,00010101000000,"База заблокирована администратором","GoD",""}
Где второй и третий "параметр" - дата начала блокировки и дата конца блокировки соответственно в формате ГГГГММДДччммсс. (вы всегда можете запустить вашу файловую базу с параметром /CЗавершитьРаботуПользователей, что бы получить этот файл и проанализировать его)
- Команда taskkill прекрасно, хотя возможно излишне "сурово" завершает работу пользователей! :) в числе прочих ее параметров, есть /FI, который позволяет достаточно гибко настроить ,какие именно процессы надо завершать. Сейчас я остановился на варианте taskkill /f /FI "IMAGENAME eq 1cv8.exe", хотя в таком случае "безвинно пострадают" сеансы, не имеющие отношения к целевой базе (если таковые имеются). Я пробовал более "элегантный" вариант: taskkill /f /FI "WINDOWTITLE eq 1С:Предприятие - Рабочая база" (Где <Рабочая база> - заголовок окна программы заданный в настройках), но он работает только в идеальных условиях (например - не "убиваются" сеансы, когда пользователь запустил 1С, система дошла до ввода пароля и на этом - все).
Кроме того, несколько стандартных "граблей" на которые я наступал в процессе:
- Пара слов о psexec. Формат вызова: psexec \\reg_srv -u username -p pass -c -f "reg_todo_t.bat". Вроде бы все понятно, но как обычно есть пара нюансов. Ключ -c копирует файл reg_todo_t.bat из каталога запуска psexec на удаленную машину перед исполнением. И копирует он его в системный каталог (system32, кажется). Поэтому ,если есть необходимость в каких-то дополнительных исполняемых файлах (например vbs), их нужно или предвариательно положить туда же, или первой строкой в reg_todo_t.bat устанавливать нужный рабочий каталог.
- Еще один важный момент. Особенностью cmd/bat файла является то, что вызвав запуск сторонней программы, он считает данную инструкцию выполненной и переходит к следующей. Нам же нужно обеспечить запуск всех наших действий СТРОГО последовательно (нет смысла запускать обновление, если еще не закончилась процедура завершения сеансов). Для этих целей нужно использовать конструкцию start /wait.
- cmd/bat файлы имеют OEM кодировку. Кирилические шрифты (в сообщения логирования, например) при открытии файла в блокноте по умолчанию будут отображаться "кракозябрами". Переключаем шрифт на terminal.
Ну, вроде бы все необходимое у нас есть. План такой:
- Блокируем доступ к центральной базе (база серверная, поэтому vbs)
- Завершаем сеансы пользователя (тоже самое - vbs)
- Обновляем конфигурацию из хранилища (cmd/bat пакетный режим конфигуратора)
- Обновляем конфигурацию базы данных (то же самое)
- Запускаем обмен (vbs)
- Снимаем блокировку базы (серверная база, поэтому vbs)
- Удаленно на региональном сервере запускаем bat/cmd/wsf (psexec) , в котором:
- блокируем доступ к базе (для файловых баз: файлик 1Cv8.cdn, для серверных см п.1, vbs)
- Завершаем сеансы (для файловых баз: taskkill, для серверных - vbs)
- Запускаем обмен (CreateObject("V83.Application") работает как для серверных, так и для файловых баз)
- Обновляем конфигурацию базы данных (см п.4, пакетный режим)
- Снимаем блокировку базы (файлик 1Cv8.cdn или vbs)
Пример всего этого (для гипотетической инфраструктуры) во вложении.
Описание вложения:
- DoIt!.bat - запускает обновление центральной и переферийной баз из хранилища tcp://srv/conf, в котором имя пользователя равно имени базы (infobase), без пароля. Так или иначе вызывает остальные файлы.
- users.vbs - скрипт, который выгоняет пользователей и устанавливает блокировку базы, либо снимает блокировку базы в зависимости от параметра (off|on).
- update.bat обновляет базу из хранилища и обновляет конфигурацию БД.
- obmen.vbs - запускает экспортную процедуру общего модуля, инициализирующую обмен по существующей настройке УРБД.
Нюансы предполагаемой инфраструктуры:
- Предполагаем наличие в сети сервера srv, с базой ibfobase.
- Предполагается так же, что на стороне удаленной площадки есть сервер reg_srv, доступный по сети, на котором:
- - в папке C:\auto есть папка Logs и файл obmen.vbs.
- - установлена 1с и база лежит в каталоге D:\1C_Bases\infobase
- - авторизация в базе настроена по авторизации операционной системы.
- Программа psexec.exe в поставку не входит, ее следует скачать отдельно.
Upd 18.04.2017
- В типовых 1С есть "прекрасная" процедура при начале работы системы: КонтрольВерсииКонфигурации.ПроверитьВерсиюКонфигурации();
Эта процедура, проверяет константу ДатаТекущейВерсии, и, если она на два или более месяца меньше текущей даты, выводит модальное окно о необходимости одновить конфигурацию... Это окно выходит внезависимости от того - запускается ли сеанс с параметрами /DisableStartupMessage и /AU- , оно просто появляется и все. И ломает всю схему. Вариантов есть несколько... С точки зрения 1С, видимо, необходимо поддерживать актуальную конфигурацию. Для тех, у кого разрешены изменения конфигурации стоит закомментировать приведенную выше строчку кода в модуле обычного приложения. У кого не разрешены: Константы.ДатаТекущейВерсии.Установить(Дата('21000101')); т.е. ставим дату конфигурации на 2100 год... Но это нужно будет делать после каждого обновления.
- При вызове экспортной процедуры с помощью vbs скрипта - в строке соединения не было параметра UC, что не давало ему запустится (т.к. на момент его запуска соединения с БД запрещены). Добавил по тексту и исправил пример во вложении.