Отключаем пользователей от базы 1С из встроенного языка: COM-коннектор, rac и расписание
Содержание
Программно завершить сеанс другого пользователя 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 фильтр должен ответить на четыре вопроса.
- Это наша база? В кластере сеансы всех баз сразу. Сверяйте имя базы.
- Это не мой сеанс? Сравните номер сеанса с
НомерСеансаИнформационнойБазы(). - Какое это приложение? Фильтр по идентификатору.
- Сколько он бездействует? Если отключаете только зависших.
Идентификаторы приложений, которые встречаются чаще всего:
| 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);
Количество = ЗавершитьСеансыБазы(Параметры);
💡 Пароль администратора кластера не храните в тексте модуля. В конфигурациях на БСП для этого есть безопасное хранилище данных; в самописной базе — хотя бы отдельный регистр сведений с доступом только для администратора.
Завершение сеанса — это обрыв. Несохранённые изменения в открытых формах пропадают, начатая транзакция откатывается. Пользователь увидит сообщение о разрыве соединения.
Безопасный порядок отключения: блокировка, пауза, обрыв
Если просто завершить сеансы, через минуту люди зайдут снова. Поэтому порядок такой.
- Запретите новые входы. Объект
БлокировкаСеансовне трогает текущие сеансы, но не пускает новые. - Дайте время сохраниться. Сообщение блокировки увидят те, кто попробует войти. Текущих пользователей предупредите заранее: штатная блокировка БСП делает это сама, в самописной базе — через рассылку или обработчик ожидания на клиенте.
- Завершите оставшихся функцией из предыдущего раздела.
- Сделайте работу — обновление, выгрузку, пересчёт.
- Снимите блокировку.
Установка блокировки:
Блокировка = Новый БлокировкаСеансов;
Блокировка.Начало = ТекущаяДата();
Блокировка.Конец = ТекущаяДата() + 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-коннектор доступен.
Порядок в конфигураторе:
- Создайте общий модуль с флажком «Сервер» (без «Вызов сервера») и положите туда
ЗавершитьСеансыБазы. - Добавьте процедуру-обработчик:
Процедура НочноеОтключениеПользователей() Экспорт
Приложения = Новый Массив;
Приложения.Добавить("1CV8C");
Приложения.Добавить("1CV8");
Приложения.Добавить("WebClient");
Параметры = Новый Структура;
Параметры.Вставить("Сервер", "srv1c");
Параметры.Вставить("ИмяБазы", "buh");
Параметры.Вставить("АдминКластера", "");
Параметры.Вставить("ПарольКластера", "");
Параметры.Вставить("Приложения", Приложения);
Параметры.Вставить("МинутПростоя", 30);
Попытка
Количество = ЗавершитьСеансыБазы(Параметры);
ЗаписьЖурналаРегистрации("Отключение пользователей",
УровеньЖурналаРегистрации.Информация, , ,
СтрШаблон("Завершено сеансов: %1", Формат(Количество, "ЧН=0; ЧГ=0")));
Исключение
ЗаписьЖурналаРегистрации("Отключение пользователей",
УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
- В ветке метаданных «Общие → Регламентные задания» создайте задание, в поле «Имя метода» выберите эту процедуру.
- Отметьте «Предопределённое» и «Использование», задайте расписание: ежедневно, время начала 23:00.
- Обновите конфигурацию базы данных.
💡 Запись в журнал регистрации нужна не для красоты. Когда утром спросят «кто меня выкинул», ответ будет с точным временем и числом завершённых сеансов.
Перед задачей проверьте, что в свойствах базы в консоли кластера не установлен флажок «Блокировка регламентных заданий включена» — иначе задание не стартует.
Файловая база и клиент-серверный вариант: в чём разница
Главное отличие — в файловом варианте нет кластера. Значит, нет агента, 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 для конкретной базы. Без фильтра код завершит сеансы во всех базах кластера.