Отключаем пользователей от базы 1С из встроенного языка: COM-коннектор, rac и расписание

· 10 мин

Содержание

Программно завершить сеанс другого пользователя 1С встроенный язык напрямую не умеет: метода «убить сеанс» в глобальном контексте нет. Принудительно завершают сеансы через кластер серверов — COM-объект V83.COMConnector и его метод TerminateSession или утилиту rac session terminate. Встроенными средствами платформы можно только получить список сеансов (ПолучитьСеансыИнформационнойБазы()) и запретить новые подключения (УстановитьБлокировкуСеансов()).

Схема для клиент-серверной базы: заблокировать вход , выбрать сеансы нужной базы по типу приложения и времени простоя, завершить их через кластер. В файловой базе кластера нет, и чужой сеанс там можно закрыть только «мягко» — руками самого клиента.

Три механизма, из которых собирается решение

У задачи три части, и за каждую отвечает свой инструмент.

ЗадачаИнструментГде работает
Узнать, кто подключёнПолучитьСеансыИнформационнойБазы()файловый и клиент-серверный вариант
Не пустить новыхобъект БлокировкаСеансов + УстановитьБлокировкуСеансов()оба варианта
Оборвать чужой сеансV83.COMConnector → TerminateSession или rac session terminateтолько клиент-сервер
Закрыть свой сеансЗавершитьРаботуСистемы() на клиентеоба варианта

Последняя строка — основа «мягкого» отключения. Клиент сам проверяет признак блокировки обработчиком ожидания и закрывается. Так устроена «Блокировка работы пользователей» в типовых конфигурациях на БСП: в БП 3.0 и ЗУП 3.1 она лежит в Администрирование → Обслуживание.

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

Как получить список сеансов информационной базы

Метод глобального контекста ПолучитьСеансыИнформационнойБазы() возвращает массив объектов СеансИнформационнойБазы. Вызывать его нужно на сервере, пользователю нужно право «Администрирование» (или привилегированный режим).

Полезные свойства сеанса:

  • 🔢 НомерСеанса — номер, по которому сеанс виден в консоли кластера;
  • 👤 Пользователь — ПользовательИнформационнойБазы или Неопределено, если в базе нет пользователей;
  • 💻 ИмяКомпьютера — откуда подключились;
  • 🧩 ИмяПриложения — тип клиента, строкой вроде 1CV8C;
  • 🕐 НачалоСеанса — дата и время входа.

Пример: вывести все подключения в сообщения.

&НаСервереБезКонтекста
Процедура ВывестиСеансыНаСервере()

    ТекущийНомер = НомерСеансаИнформационнойБазы();

    Для Каждого Сеанс Из ПолучитьСеансыИнформационнойБазы() Цикл
        ИмяПользователя = ?(Сеанс.Пользователь = Неопределено,
            "<без авторизации>", Сеанс.Пользователь.Имя);
        Метка = ?(Сеанс.НомерСеанса = ТекущийНомер, " (это вы)", "");
        Сообщить(СтрШаблон("%1%2 | %3 | %4 | %5 | %6",
            Формат(Сеанс.НомерСеанса, "ЧГ=0"), Метка,
            ИмяПользователя,
            ПредставлениеПриложения(Сеанс.ИмяПриложения),
            Сеанс.ИмяКомпьютера,
            Формат(Сеанс.НачалоСеанса, "ДЛФ=DT")));
    КонецЦикла;

КонецПроцедуры

ПредставлениеПриложения() превращает 1CV8C в читаемое «Тонкий клиент». Иногда встречается название «объект СеансыИнформационнойБазы» — такого объекта нет, есть именно этот метод и тип элемента СеансИнформационнойБазы.

⚠️ Метод показывает, кто подключён, но завершить найденный сеанс через него нельзя. Время последней активности тоже не отдаёт — его берут из кластера (см. ниже).

Кого завершать, а кого оставить: фильтр активных подключений

Самая частая ошибка самописного «выгонятеля» — он рвёт всё подряд, включая себя и фоновые задания. Перед TerminateSession фильтр должен ответить на четыре вопроса.

  1. Это наша база? В кластере сеансы всех баз сразу. Сверяйте имя базы.
  2. Это не мой сеанс? Сравните номер сеанса с НомерСеансаИнформационнойБазы().
  3. Какое это приложение? Фильтр по идентификатору.
  4. Сколько он бездействует? Если отключаете только зависших.

Идентификаторы приложений, которые встречаются чаще всего:

AppIDЧто этоЗавершать?
1CV8Cтонкий клиентда, основная цель
1CV8толстый клиентда
WebClientвеб-клиентда
Designerконфигуратортолько осознанно: рядом может идти обновление
COMConnectionвнешнее COM-соединениепо ситуации: это может быть обмен
BackgroundJobфоновое заданиенет — в том числе ваше регламентное задание
SrvrConsoleконсоль кластеранет

Никогда не завершайте BackgroundJob без разбора — так легко оборвать собственное регламентное задание на середине, а заодно обмен или закрытие месяца .

Завершение сеансов пользователей 1С через COM-коннектор

Это основной способ для клиент-серверной базы. Код выполняется на сервере 1С, поэтому comcntr.dll должна быть зарегистрирована на том компьютере, где работает рабочий процесс, и той же разрядности:

regsvr32 "C:\Program Files\1cv8\8.3.xx.xxxx\bin\comcntr.dll"

Номер версии в пути подставьте свой — он должен совпадать с версией платформы сервера.

Общий модуль, флажок «Сервер»:

// Параметры — структура:
//   Сервер, ИмяБазы, АдминКластера, ПарольКластера,
//   Приложения       — массив AppID, например "1CV8C", "1CV8", "WebClient",
//   МинутПростоя     — 0 = завершать всех подходящих.
// Возвращает количество завершённых сеансов.
Функция ЗавершитьСеансыБазы(Параметры) Экспорт

    ТекущийНомер = НомерСеансаИнформационнойБазы();
    Завершено = 0;

    Коннектор = Новый COMОбъект("V83.COMConnector");
    Агент = Коннектор.ConnectAgent("tcp://" + Параметры.Сервер + ":1540");

    Для Каждого Кластер Из Агент.GetClusters().Выгрузить() Цикл

        Агент.Authenticate(Кластер, Параметры.АдминКластера, Параметры.ПарольКластера);

        Для Каждого Сеанс Из Агент.GetSessions(Кластер).Выгрузить() Цикл

            Если НРег(Сеанс.infoBase.Name) <> НРег(Параметры.ИмяБазы) Тогда
                Продолжить;
            КонецЕсли;
            Если Сеанс.SessionID = ТекущийНомер Тогда
                Продолжить;
            КонецЕсли;
            Если Параметры.Приложения.Найти(Сеанс.AppID) = Неопределено Тогда
                Продолжить;
            КонецЕсли;
            Если Параметры.МинутПростоя > 0
                И ТекущаяДата() - Сеанс.LastActiveAt < Параметры.МинутПростоя * 60 Тогда
                Продолжить;
            КонецЕсли;

            Агент.TerminateSession(Кластер, Сеанс);
            Завершено = Завершено + 1;

        КонецЦикла;

    КонецЦикла;

    Возврат Завершено;

КонецФункции

Что здесь важно:

  • 🔌 1540 — порт агента сервера по умолчанию. Если при установке его меняли, укажите свой.
  • 🔐 Authenticate — учётная запись администратора кластера. Если администраторы кластера не заданы, передайте пустые строки.
  • 📦 GetClusters() и GetSessions() возвращают COMSafeArray; .Выгрузить() превращает его в обычный массив.
  • ⏱ LastActiveAt — время последней активности сеанса по часам сервера, поэтому сравнение идёт с ТекущаяДата() на сервере, а не с датой сеанса пользователя.

Вызов:

Приложения = Новый Массив;
Приложения.Добавить("1CV8C");
Приложения.Добавить("1CV8");
Приложения.Добавить("WebClient");

Параметры = Новый Структура;
Параметры.Вставить("Сервер", "srv1c");
Параметры.Вставить("ИмяБазы", "buh");
Параметры.Вставить("АдминКластера", "");
Параметры.Вставить("ПарольКластера", "");
Параметры.Вставить("Приложения", Приложения);
Параметры.Вставить("МинутПростоя", 0);

Количество = ЗавершитьСеансыБазы(Параметры);

💡 Пароль администратора кластера не храните в тексте модуля. В конфигурациях на БСП для этого есть безопасное хранилище данных; в самописной базе — хотя бы отдельный регистр сведений с доступом только для администратора.

Завершение сеанса — это обрыв. Несохранённые изменения в открытых формах пропадают, начатая транзакция откатывается. Пользователь увидит сообщение о разрыве соединения.

Безопасный порядок отключения: блокировка, пауза, обрыв

Если просто завершить сеансы, через минуту люди зайдут снова. Поэтому порядок такой.

  1. Запретите новые входы. Объект БлокировкаСеансов не трогает текущие сеансы, но не пускает новые.
  2. Дайте время сохраниться. Сообщение блокировки увидят те, кто попробует войти. Текущих пользователей предупредите заранее: штатная блокировка БСП делает это сама, в самописной базе — через рассылку или обработчик ожидания на клиенте.
  3. Завершите оставшихся функцией из предыдущего раздела.
  4. Сделайте работу — обновление, выгрузку, пересчёт.
  5. Снимите блокировку.

Установка блокировки:

Блокировка = Новый БлокировкаСеансов;
Блокировка.Начало = ТекущаяДата();
Блокировка.Конец = ТекущаяДата() + 3600; // на час
Блокировка.Сообщение = "Идёт обновление базы. Вход откроется после 21:00.";
Блокировка.КодРазрешения = "service";
Блокировка.Установлена = Истина;
УстановитьБлокировкуСеансов(Блокировка);

Снятие — та же процедура с Установлена = Ложь. Текущее состояние читает ПолучитьБлокировкуСеансов().

Код разрешения пропускает администратора во время блокировки. Его передают параметром запуска /UC:

"C:\Program Files\1cv8\common\1cestart.exe" ENTERPRISE /S"srv1c\buh" /UCservice

Задайте Конец всегда. Блокировка без срока, забытая после ночного обновления, утром оставит всю бухгалтерию без входа.

Зависшие и спящие сеансы

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

Признаки, по которым их находят в кластере:

  • 💤 LastActiveAt — давно не было обращений. Порог 60–120 минут для рабочего дня обычно разумен, ночью можно 15–30.
  • 🛌 Hibernate — сеанс в спящем состоянии: соединение с клиентом пропало, но сервер держит контекст в надежде на восстановление.
  • 🔒 blockedByDBMS — сеанс ждёт блокировку СУБД. Не путать с простоем: он, наоборот, пытается работать.

Для отбора по простою в функции уже есть параметр МинутПростоя. Пример: ночью отключить всех, кто не трогал базу больше 30 минут:

Параметры.Вставить("МинутПростоя", 30);

⚠️ Сеанс, который висит в ожидании блокировки, может быть частью долгой операции — проведения документов за месяц, закрытия периода. Если отключаете по blockedByDBMS, сначала посмотрите, кто держит блокировку: обрывать нужно его, а не очередь за ним. И предупредите людей: оборванная транзакция откатится, работу придётся начать заново.

Диагностика: выберите симптом

Отключение пользователей 1С по расписанию через регламентное задание

Регулярную задачу — «каждую ночь в 23:00 выгонять забывших выйти» — удобно повесить на регламентное задание. Оно выполняется в фоновом сеансе на сервере, поэтому COM-коннектор доступен.

Порядок в конфигураторе:

  1. Создайте общий модуль с флажком «Сервер» (без «Вызов сервера») и положите туда ЗавершитьСеансыБазы.
  2. Добавьте процедуру-обработчик:
Процедура НочноеОтключениеПользователей() Экспорт

    Приложения = Новый Массив;
    Приложения.Добавить("1CV8C");
    Приложения.Добавить("1CV8");
    Приложения.Добавить("WebClient");

    Параметры = Новый Структура;
    Параметры.Вставить("Сервер", "srv1c");
    Параметры.Вставить("ИмяБазы", "buh");
    Параметры.Вставить("АдминКластера", "");
    Параметры.Вставить("ПарольКластера", "");
    Параметры.Вставить("Приложения", Приложения);
    Параметры.Вставить("МинутПростоя", 30);

    Попытка
        Количество = ЗавершитьСеансыБазы(Параметры);
        ЗаписьЖурналаРегистрации("Отключение пользователей",
            УровеньЖурналаРегистрации.Информация, , ,
            СтрШаблон("Завершено сеансов: %1", Формат(Количество, "ЧН=0; ЧГ=0")));
    Исключение
        ЗаписьЖурналаРегистрации("Отключение пользователей",
            УровеньЖурналаРегистрации.Ошибка, , ,
            ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;

КонецПроцедуры
  1. В ветке метаданных «Общие → Регламентные задания» создайте задание, в поле «Имя метода» выберите эту процедуру.
  2. Отметьте «Предопределённое» и «Использование», задайте расписание: ежедневно, время начала 23:00.
  3. Обновите конфигурацию базы данных.

💡 Запись в журнал регистрации нужна не для красоты. Когда утром спросят «кто меня выкинул», ответ будет с точным временем и числом завершённых сеансов.

Перед задачей проверьте, что в свойствах базы в консоли кластера не установлен флажок «Блокировка регламентных заданий включена» — иначе задание не стартует.

Файловая база и клиент-серверный вариант: в чём разница

Главное отличие — в файловом варианте нет кластера. Значит, нет агента, TerminateSession и rac. Чужой сеанс из кода оборвать нечем.

ВозможностьКлиент-серверФайловая база
Список сеансов ПолучитьСеансыИнформационнойБазы()естьесть
Блокировка новых сеансовестьесть
Принудительное завершение чужого сеансаCOM-коннектор, racнет
Время простоя сеансаLastActiveAt из кластеранет
Регламентные задания по расписаниювыполняет сервертолько пока открыт клиентский сеанс

Что остаётся для файловой базы:

  • ✅ «Мягкий» путь: блокировка плюс обработчик ожидания на клиенте, который видит блокировку и вызывает ЗавершитьРаботуСистемы(Ложь). Штатная обработка БСП работает именно так.
  • ⚠️ Жёсткий путь — снять процессы 1cv8.exe / 1cv8c.exe на терминальном сервере или в «Диспетчере задач». Это обрыв без сохранения: делайте только когда все предупреждены, и никогда — во время записи в базу, иначе есть риск повредить файл 1Cv8.1CD.

Вариант без кода: rac для клиент-серверной базы

Если на сервере Linux или COM-коннектор поставить нельзя, то же самое делает утилита rac. Ей нужна запущенная служба сервера администрирования ras (порт по умолчанию 1545).

rem 1. UUID кластера
rac localhost:1545 cluster list

rem 2. UUID нужной базы
rac localhost:1545 infobase summary list --cluster=<uuid-кластера>

rem 3. Сеансы этой базы
rac localhost:1545 session list --cluster=<uuid-кластера> --infobase=<uuid-базы>

rem 4. Завершить конкретный сеанс
rac localhost:1545 session terminate --cluster=<uuid-кластера> --session=<uuid-сеанса>

Если в кластере заданы администраторы, к командам добавляют --cluster-user и --cluster-pwd. Остальные ключи смотрите в rac help session. Из 1С такую команду можно вызвать через ЗапуститьПриложение() на сервере, но разбирать текстовый вывод сложнее, чем работать с COM-объектами.

Частые вопросы

Можно ли завершить сеанс пользователя без прав администратора кластера?
Нет. Если в кластере заданы администраторы, Authenticate без их логина и пароля не пройдёт. Права «Администрирование» в самой базе для этого недостаточно.
Освобождается ли лицензия сразу после завершения сеанса?
Да, лицензия сеанса возвращается в пул после его завершения. Сеанс в спящем состоянии лицензию держит, поэтому именно спящие и забытые сеансы чаще всего «съедают» лицензии.
Как отключить пользователей только одной базы, если на сервере их двадцать?
Отфильтруйте сеансы по Сеанс.infoBase.Name или используйте GetInfoBaseSessions для конкретной базы. Без фильтра код завершит сеансы во всех базах кластера.
Почему пользователь после отключения сразу заходит снова?
Завершение сеанса не запрещает новый вход. Перед отключением установите блокировку сеансов с понятным сообщением и сроком окончания.
Как найти, кто держит базу, если вход в неё закрыт?
Откройте консоль администрирования серверов 1С: ветка базы → «Сеансы». Там видны пользователь, компьютер, приложение и время последней активности — те же данные, что получает код.