Думаю, всем вам известен такой программный продукт, как 1С: Предприятие 8.2. И, наверное, многим из вас известен тот факт, что к 1С: Предприятию можно подключиться, используя OLE/COM-соединение. А многие ли из вас знают, что с помощью OLE/COM-соединения можно не только выполнять программный код 1С, но и “управлять” сервером 1С: Предпрития? К примеру, можно подключиться к Агенту кластера серверов 1С: Предприятия, получить список открытых клиентских сессий, прочитать информацию о выданных им лицензиях… К тому же, наличие варианта подключения посредством OLE/COM-соединения расширяет в арсенале программиста добавляет возможность выбора языка программирования, отличного от встроенного языка 1С: Предприятия. Можно выбрать любой язык, который способен работать с OLE/COM-компонентами: будь то VB.Net, C#.Net, или Java, или даже… Perl. Да, вы не ослышались. Именно Perl.
Итак…
Задача.
Необходимо реализовать автоматический рестарт службы Агент сервера 1С: Предприятия 8.2 с помощью планировщика задач Windows. Но перед рестартом необходимо проверить, не работает ли кто-нибудь в базе Base, расположенной на сервере 1С: Предприятия. Если кто-нибудь работает, то перезапуск службы недопустим.
Решение.
У вас может закрасться вопрос, мол, зачем нужно периодически перезапускать службу Агента сервера? Дело в том, что в версии 1С: Предприятие 8.2 х64 есть одна “маленькая” ошибка. Она возникает при динамическом обновлении информационной базы и приводит БД к невозможности обновления и работы в ней. Разработчики официально (в личной переписке с ними) заявили, что данная ошибка не планируется к исправлению в версии 8.2. Придется ждать и “выживать” до официального релиза 8.3. Я-то знаю способ исправления этой ошибки (если надо — расскажу в комментариях или апдейте статьи). Но, как заверяют разработчики, данный способ обхода может разрушить базу данных совсем. У меня за год использования этого способа обхода база не разрушилась. Но не об этом статья.
Итак. Задача поставлена. Основной проблемой для меня стало условие проверки существующих подключений к определенной БД. Для реализации поставленной задачи я решил не использовать встроенный язык 1С: Предприятия, ни один из .Net-языков, а также Java (only console, only true linux-way).
В синтаксис-помощнике 1С: Предприятия был найден метод проверки наличия подключений к БД, но он предполагал использование OLE/COM-соединения к Агенту сервера 1С: Предприятия. Что ж… Приступим.
GetInfoBaseConnections (GetInfoBaseConnections)
Синтаксис:
GetInfoBaseConnections(<Кластер>, <ИнформационнаяБаза>)
Параметры:
<Кластер> (обязательный)
Тип: Кластер серверов. Кластер серверов, для которого должен быть получен массив описаний соединений.
<ИнформационнаяБаза> (обязательный)
Тип: Описание информационной базы. Информационная база, для которой должен быть получен массив описаний соединений.
Возвращаемое значение:
Тип: COMSafeArray. Массив описаний соединений кластера. Каждое описание соединения представлено объектом с интерфейсом Описание соединения.
Описание:
Получает массив описаний соединений информационной базы.
Доступность:
Интеграция.
Для работы с OLE/COM-объектами средствами Perl нам понадобиться задействовать модуль Win32::OLE. В используемой мной сборке StrawberryPerl данный модуль уже был предустановлен. Но даже если это не так, можно установить его через CPAN:
C:Perlperlbincpan Win32::OLE
Чтобы получить список соединений базы данных 1С, нам нужно:
- Создать COM-подключение к объекту V82.COMConnector;
- Подключиться к агенту кластера серверов 1С: Предприятия;
- Получить объект кластера 1С;
- Авторизоваться на кластере;
- Получить список баз 1С на этом кластере;
- Найти необходимую нам базу;
- Получить список активных соединений к этой базе данных.
Вот код с комментариями, который получает список активных соединений клиентов с базой данных 1С: Предприятия, расположенной на сервере 1С: Предприятия.
use strict;
use warnings;
use Win32::OLE;
use Data::Dumper;
sub getConnectionsCount {
# имя сервера (с портом) и имя базы будем получать из параметров метода
my ($server, $dbname) = @_;
# создаем COM-соединение
my $ole1c = Win32::OLE->new("V82.COMConnector") or die "Could not create OLE-connector!n";
# создаем объект Агента сервера 1С:Предприятия
my $_agent = $ole1c->ConnectAgent($server) or die "Could not connect to server!n" . cnv(Dumper $ole1c->ErrorDescription());
# получаем объект кластера (у меня один кластер)
my $_cluster = $_agent->GetClusters()->[0] or die "Could not get cluster 0 from arrayn";
# авторизуемся на кластере серверов.
# Авторизоваться надо с помощь логина и пароля Администратора кластера серверов,
# которого можно задать в утилите Администрирования сервера 1С:Предприятия.
# не путайте этого администратора с администратором базы данных, что заводится
# через конфигуратор в пользователях.
# У меня нет администраторов, оставляю пустыми параметры логина и пароля.
$_agent->Authenticate($_cluster, "", "");
# получаем список баз данных, расположенных в данном кластере
my $_basesinfo = $_agent->GetInfoBases($_cluster);
# найдем нашу базу данных
my @_bases = grep { defined $_->{Name} && $_->{Name} =~ m/^$dbname$/ } @$_basesinfo;
# она точно будет одна
my $_base = $_bases[0];
# заведем счетчик подключений
my $connCounter = 0;
# получим все активные подключения или сразу вернем 0
my $_baseconns = $_agent->GetInfoBaseConnections($_cluster, $_base) or return 0;
# “отсечем” все соединения по типу приложения, на которые можно не обращать внимание.
# если эти подключения есть, то можно смело перегружать службу
# Агента сервера 1С:Предприятия
foreach (@$_baseconns) {
# нам не важны планировщики задач и подключения через консоль кластера
if ($_->{Application} !~ m/JobScheduler/ && $_->{Application} !~ m/SrvrConsole/) {
$connCounter++;
}
}
return $connCounter;
}
# вызов очень простоой.
# только порт нужно указывать тот, который слушает агент кластера серверов 1С:Предприятия
print “There are “ . getConnectionsCount(“localhost:1540”, “Base”) . “ active connectionsn”;
Перезапустить службу Агента можно с помощью команд “net start” и “net stop”:
net stop <ИмяСлужбы>
net start <ИмяСлужбы>
Полный код, выполняющий поставленную задачу я расположил на Bitbucket-е.
Автор: bvn13