Как программно завершить сеансы пользователей в серверной базе 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

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

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

Решение 1: Использование объекта V83.COMConnector для управления сеансами

Самый надежный и универсальный способ управления сеансами — это использование COM-объекта V83.COMConnector (или V82.COMConnector/V8.COMConnector в зависимости от версии платформы). Этот объект предоставляет программный доступ к функциям администрирования кластера серверов 1С.

Разберем по шагам, как создать скрипт для завершения сеансов.

  1. Подключение к агенту сервера 1С

    Первым делом необходимо создать экземпляр COM-объекта и подключиться к агенту сервера, на котором работает кластер 1С. Для этого используется метод ConnectAgent().

    
    // Создаем COM-объект для подключения
    Connector = Новый COMОбъект("V83.COMConnector");
    
    // Подключаемся к агенту сервера. Укажите имя вашего сервера 1С.
    Агент = Connector.ConnectAgent("ИмяСервера1С");
    

    Важно: код, который выполняет эти действия, должен запускаться от имени пользователя, обладающего правами администратора кластера 1С. В противном случае на этапе подключения или при попытке получить доступ к кластерам возникнет ошибка доступа.

  2. Получение списка кластеров и рабочих процессов

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

    
    // Получаем список кластеров на сервере
    МассивКластеров = Агент.GetClusters();
    
    // Проходим по всем кластерам (обычно он один)
    Для Каждого Кластер Из МассивКластеров Цикл
        // Для аутентификации в кластере можно указать имя и пароль администратора кластера,
        // если они заданы. Если нет, то оставляем пустыми.
        Агент.Authenticate(Кластер, "", "");
        
        // Получаем рабочие процессы этого кластера
        МассивРабочихПроцессов = Агент.GetWorkingProcesses(Кластер);
    КонецЦикла;
    
  3. Получение и анализ соединений

    Теперь, имея доступ к рабочим процессам, мы можем получить список всех активных соединений с информационными базами. Метод GetInfoBaseConnections() возвращает массив объектов, каждый из которых описывает один активный сеанс.

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

  4. Завершение сеанса методом Разорвать()

    У объекта, описывающего соединение (IInfoBaseConnection), есть метод Разорвать() (Disconnect() в англоязычном синтаксисе). Именно он и выполняет принудительное завершение сеанса.

Посмотрим на полный пример кода, который объединяет все эти шаги.


Процедура ЗавершитьСеансы()
    
    ИмяСервера1С = "ИмяВашегоСервера";
    ИмяИнформационнойБазы = "ИмяВашейБазы";
    
    Попытка
        Connector = Новый COMОбъект("V83.COMConnector");
    Исключение
        Сообщить("Не удалось создать V83.COMConnector. " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    Попытка
        Агент = Connector.ConnectAgent(ИмяСервера1С);
    Исключение
        Сообщить("Не удалось подключиться к агенту сервера " + ИмяСервера1С + ". " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;

    // Получаем список кластеров
    МассивКластеров = Агент.GetClusters();

    Для Каждого Кластер Из МассивКластеров Цикл
        
        // Аутентификация в кластере
        Агент.Authenticate(Кластер, "", "");
        
        // Получаем список информационных баз в кластере
        МассивИнформационныхБаз = Агент.GetInfoBases(Кластер);
        
        // Ищем нашу базу по имени
        НужнаяБаза = Неопределено;
        Для Каждого ИБ Из МассивИнформационныхБаз Цикл
            Если ИБ.Name = ИмяИнформационнойБазы Тогда
                НужнаяБаза = ИБ;
                Прервать;
            КонецЕсли;
        КонецЦикла;
        
        Если НужнаяБаза = Неопределено Тогда
            Сообщить("Информационная база '" + ИмяИнформационнойБазы + "' не найдена в кластере.");
            Продолжить;
        КонецЕсли;
        
        // Получаем все соединения для нужной базы
        МассивСоединений = Агент.GetInfoBaseConnections(Кластер, НужнаяБаза);

        // Получаем номер текущего соединения, чтобы не завершить самих себя
        НомерТекущегоСоединения = СокрЛП(Строка(ПолучитьНомерСоединенияИнформационнойБазы()));

        // Перебираем все сеансы
        Для Каждого Соединение Из МассивСоединений Цикл
            // Сравниваем номер соединения
            Если СокрЛП(Строка(Соединение.ConnID)) <> НомерТекущегоСоединения Тогда
                // Завершаем сеанс
                Попытка
                    Агент.Disconnect(Кластер, Соединение);
                    Сообщить("Сеанс пользователя '" + Соединение.UserName + "' (ID: " + Соединение.ConnID + ") успешно завершен.");
                Исключение
                    Сообщить("Не удалось завершить сеанс (ID: " + Соединение.ConnID + "). " + ОписаниеОшибки());
                КонецПопытки;
            КонецЕсли;
        КонецЦикла;
    КонецЦикла;
    
КонецПроцедуры

Решение 2: Упрощенный вариант без поиска базы

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

Рассмотрим упрощенный скриптовый вариант. Он отличается тем, что мы перебираем рабочие процессы, а не ищем конкретную информационную базу.


Процедура ЗавершитьСеансыУпрощенно()
    
    ИмяСервера1С = "ИмяВашегоСервера";
    ИмяИнформационнойБазы = "ИмяВашейБазы"; // Используется для фильтрации
    
    Connector = Новый COMОбъект("V83.COMConnector");
    Агент = Connector.ConnectAgent(ИмяСервера1С);
    
    МассивКластеров = Агент.GetClusters();
    Для Каждого Кластер Из МассивКластеров Цикл
        
        Агент.Authenticate(Кластер, "", "");
        МассивРабочихПроцессов = Агент.GetWorkingProcesses(Кластер);
        
        Для Каждого Процесс Из МассивРабочихПроцессов Цикл
            // Получаем соединения конкретного рабочего процесса
            МассивСоединений = Агент.GetWorkingProcessConnections(Кластер, Процесс);
            
            Для Каждого Соединение Из МассивСоединений Цикл
                // Проверяем, что соединение относится к нашей базе
                Если Соединение.InfoBase.Name = ИмяИнформационнойБазы Тогда
                    // Исключаем текущий сеанс по имени приложения
                    Если Соединение.AppName <> "COMConnector" Тогда
                        Попытка
                            Агент.Disconnect(Кластер, Соединение);
                            Сообщить("Завершен сеанс: " + Соединение.UserName);
                        Исключение
                            // Обработка ошибки
                        КонецПопытки;
                    КонецЕсли;
                КонецЕсли;
            КонецЦикла;
        КонецЦикла;
    КонецЦикла;
    
КонецПроцедуры

В этом примере мы используем другой критерий для исключения текущего сеанса — по имени приложения (AppName). Сеанс, установленный через COMConnector, будет иметь соответствующее имя, в то время как сеансы обычных пользователей — "1CV8" (толстый клиент), "1CV8C" (тонкий клиент) или "WebClient".

Дополнительные рекомендации

Используя эти подходы, вы можете создать надежный механизм для автоматического управления сеансами пользователей, что значительно упростит администрирование серверных баз 1С.

← На главную