«Жемчужный» доступ к 1С: Предприятию 8.2

Думаю, всем вам известен такой программный продукт, как 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С: Предприятия. Что ж… Приступим.

Выдержка из синтаксис-помощника

Соединение с агентом сервера (IServerAgentConnection)
GetInfoBaseConnections (GetInfoBaseConnections)
Синтаксис:

GetInfoBaseConnections(<Кластер>, <ИнформационнаяБаза>)

Параметры:

<Кластер> (обязательный)
Тип: Кластер серверов. Кластер серверов, для которого должен быть получен массив описаний соединений.

<ИнформационнаяБаза> (обязательный)
Тип: Описание информационной базы. Информационная база, для которой должен быть получен массив описаний соединений.

Возвращаемое значение:
Тип: COMSafeArray. Массив описаний соединений кластера. Каждое описание соединения представлено объектом с интерфейсом Описание соединения.

Описание:
Получает массив описаний соединений информационной базы.

Доступность:
Интеграция.

Для работы с OLE/COM-объектами средствами Perl нам понадобиться задействовать модуль Win32::OLE. В используемой мной сборке StrawberryPerl данный модуль уже был предустановлен. Но даже если это не так, можно установить его через CPAN:

C:\Perl\perl\bin\cpan 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 array\n";     # авторизуемся на кластере серверов.      # Авторизоваться надо с помощь логина и пароля Администратора кластера серверов,     # которого можно задать в утилите Администрирования сервера 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 connections\n”; 

Перезапустить службу Агента можно с помощью команд “net start” и “net stop”:

net stop <ИмяСлужбы> net start <ИмяСлужбы> 

Полный код, выполняющий поставленную задачу я расположил на Bitbucket-е.

ссылка на оригинал статьи http://habrahabr.ru/post/174857/

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *