В процессе администрирования клиент-серверных баз данных на платформе 1С:Предприятие 8.2 (особенно при работе в связке с MS SQL Server и службами удаленных рабочих столов RDS) часто возникает неприятная ситуация: пользователи закрывают программу или отключаются от терминального сервера, но их сессии продолжают «висеть» в консоли администрирования 1С. Такие «зомби-сессии» не просто засоряют список активных пользователей, но и продолжают удерживать дефицитные клиентские лицензии (например, ключи защиты «Альфа-Авто» или программные лицензии 1С), блокируя работу других сотрудников.
Обычная перезагрузка сервера или установка блокировки соединений не всегда помогают оперативно решить проблему, а ручное удаление сеансов через консоль администрирования отнимает много времени у системного администратора. В этой статье мы подробно разберем, почему возникает эта проблема и как автоматизировать очистку зависших соединений с помощью программных скриптов и системных настроек Windows.
Прежде чем переходить к устранению проблемы, проанализируем ситуацию и выделим основные причины появления зависших сессий:
splwow64.exe. После закрытия 1С этот процесс продолжает работать в фоне и не дает операционной системе завершить терминальный сеанс пользователя.---
Для оперативного освобождения лицензий можно использовать специальный скрипт (обработку), который подключается к агенту сервера 1С через COM-объект и принудительно завершает сеансы всех пользователей, кроме текущего администратора. Данную обработку можно настроить на запуск по расписанию (например, перед выполнением резервного копирования).
Рассмотрим подробнее программный код, который выполняет эту задачу:
СоединениеНомер = НомерСоединенияИнформационнойБазы;
СоединениеПараметры = Инт_Строка.СтрокаСоответствие(СтрокаСоединенияИнформационнойБазы);
СерверПортИмя = СоединениеПараметры.Получить("Srvr");
БазаИмя = НРег(СоединениеПараметры.Получить("Ref"));
// Инициализируем COM-соединитель для платформы 8.2
Соединитель = Новый COMОбъект("V82.COMConnector");
РазделительПозиция = Найти(СерверПортИмя, ":");
Если РазделительПозиция > 0 Тогда
СерверИмя = Лев(СерверПортИмя, РазделительПозиция - 1);
СерверКластерПорт = Число(Сред(СерверПортИмя, РазделительПозиция + 1));
Иначе
СерверКластерПорт = Соединитель.RMngrPortDefault;
КонецЕсли;
СерверАгентИмя = СерверИмя;
Если ЗначениеЗаполнено(Вход_СерверАгентПорт) Тогда
СерверАгентИмя = СерверАгентИмя + ":" + Инт_Строка.ЧислоСтрока(Вход_СерверАгентПорт);
КонецЕсли;
// Подключаемся к агенту сервера приложений
Агент = Соединитель.ConnectAgent(СерверАгентИмя);
Кластеры = Агент.GetClusters();
Для Каждого Кластер Из Кластеры Цикл
Если Кластер.MainPort <> СерверКластерПорт Тогда
Продолжить;
КонецЕсли;
// Авторизуемся в кластере
Агент.Authenticate(Кластер, Вход_КластерАдминистратор, Вход_КластерАдминистраторПароль);
Процессы = Агент.GetWorkingProcesses(Кластер);
Для Каждого Процесс Из Процессы Цикл
// Подключаемся к рабочему процессу
КластерСоединение = Соединитель.ConnectWorkingProcess("tcp://" + СерверИмя + ":" + Инт_Строка.ЧислоСтрока(Процесс.MainPort));
КластерСоединение.AddAuthentication(Вход_Администратор.ПользовательИмяИБ, Вход_АдминистраторПароль);
ИБОписание = КластерСоединение.CreateInfoBaseInfo();
ИБОписание.Name = БазаИмя;
// Получаем список всех активных соединений
Соединения = КластерСоединение.GetInfoBaseConnections(ИБОписание);
Для Каждого Соединение Из Соединения Цикл
// Отключаем все соединения, кроме текущего сеанса администратора
Если Соединение.ConnId <> СоединениеНомер Тогда
КластерСоединение.Disconnect(Соединение);
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЦикла;
Важное примечание по авторизации: Если в вашей организации используется сквозная доменная (Active Directory) авторизация, при создании COM-соединения параметры имени пользователя и пароля на стороне клиента можно передавать пустыми. В этом случае 1С автоматически подтянет учетные данные текущей учетной записи Windows. Если же код выполняется на сервере (в фоновом задании), библиотека comcntr.dll будет использовать права служебной учетной записи, из-под которой запущен `rphost.exe` (например, USR1CV8). Для корректной работы в таком сценарии рекомендуется настроить библиотеку comcntr.dll как COM+ приложение в службах компонентов Windows с указанием выделенной доменной учетной записи администратора.
---
Иногда в процессе эксплуатации серверов 1С возникает специфический сбой: сеансы пользователей теряют связь с рабочим процессом (rphost.exe), но продолжают числиться активными на уровне кластера. Посмотрим на пример кода, который находит и принудительно удаляет сессии, у которых рабочий процесс не определен:
Для Каждого Кластер Из Кластеры Цикл
Агент.Authenticate(Кластер, Вход_КластерАдминистратор, Вход_КластерАдминистраторПароль);
Сеансы = Агент.GetSessions(Кластер);
Для Каждого Сеанс Из Сеансы Цикл
// Проверяем, привязан ли сеанс к рабочему процессу
Если Сеанс.process = Неопределено Тогда
// Принудительно завершаем зависшую сессию
Агент.TerminateSession(Кластер, Сеанс);
Сообщить("Успешно удалена зависшая сессия пользователя: " + Сеанс.UserName);
КонецЕсли;
КонецЦикла;
КонецЦикла;
Использование метода TerminateSession позволяет безопасно завершить логические сеансы на сервере 1С без необходимости перезапуска всей службы.
---
Если ваши пользователи работают в терминальном режиме (RDS) и сессии 1С «зависают» из-за того, что RDP-сеанс не закрывается до конца, причиной почти наверняка является системный процесс печати splwow64.exe. Настроим операционную систему Windows Server на автоматическое и быстрое завершение этого процесса при выходе пользователя из 1С.
Для этого выполним следующие шаги в системном реестре сервера:
Win + R, введите regedit и нажмите Enter).HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print.SplWOW64TimeOut (тип DWORD (32 бита)) и установите его значение равным 1. Это уменьшит таймаут ожидания закрытия процесса печати до минимума.HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\SysProcs.SPLWOW64.EXE (тип DWORD (32 бита)) и установите его значение равным 0. Данная настройка указывает операционной системе принудительно закрывать этот процесс при выходе пользователя из терминальной сессии.После внесения изменений в реестр рекомендуется перезагрузить терминальный сервер для применения настроек.
---
Чтобы исключить появление «мертвых душ» из-за некорректного закрытия окон RDP пользователями, настроим принудительное завершение отключенных сеансов на уровне операционной системы.
Разберем по шагам настройку локальной групповой политики на терминальном сервере:
gpedit.msc.Теперь, если пользователь закроет терминал крестиком, система подождет 10 минут и полностью завершит его сеанс, автоматически закрыв зависшее приложение 1С и освободив используемую им лицензию.
---
Для борьбы с разрывами связи на уровне сетевых сокетов (когда клиент отключился физически, а сервер 1С продолжает ждать от него данных) мы можем настроить параметры TCP Keep-Alive в Windows Server. Это позволит серверу быстрее определять потерю связи с клиентом.
Для этого в реестре по пути HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters создадим два параметра типа DWORD:
KeepAliveTime со значением 300000 (время ожидания перед отправкой проверочных пакетов снижается до 5 минут);KeepAliveInterval со значением 1000 (интервал повторных проверок — 1 секунда).Эти системные меры в комплексе с периодическим запуском скрипта очистки гарантируют стабильную работу сервера 1С:Предприятие 8.2 без зависших сессий и нехватки лицензий.