gifts2017

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

Опубликовал Rabajaba Caspersky (Rabajaba) в раздел Программирование - Практика программирования

Как отключить пользователей программно в клиент-серверном варианте работы 1С 8.2.

Причины возникновения проблемы

Лично у меня на релизах от 8.2.9.х до текущего 8.2.12.96 не всегда происходит полное отключение сеансов. Например, устанавливаю обновление, умный конфигуратор мне выдает кнопку "Завершить сеансы и продолжить", после нажатия на которую остается несколько подключенных соединений.

Также в течение дня часто остаются соединения по закрытым сеансам.

Зачем это нужно

Для себя нашел два пути применения:

1. Перед инсталляцией обновлений необходимо отключить пользователей от системы;

2. Регламентное задание, отвечающее за резервное копирование, должно отключить все подключенные сеансы.

В первом случае удобство состоит в том, что есть кнопка в режиме предприятия, нажав на которую происходит полное завершение.

Как это сделать

Первое, что нам нужно - это определить имя базы и сервер, на котором она расположена. Для этого разбираем строку соединения базы.

 

Если Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr") > 0 Тогда
   
// серверный вариант
   
Поиск1 = Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr=");
   
ПодстрокаПоиска = Сред(СтрокаСоединенияИнформационнойБазы(), Поиск1 + 6);
   
ИмяСервера = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1);
   
// теперь ищем имя базы
   
Поиск1 = Найти(СтрокаСоединенияИнформационнойБазы(), "Ref=");
   
ПодстрокаПоиска = Сред(СтрокаСоединенияИнформационнойБазы(), Поиск1 + 5);
   
ИмяБазы = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1);
Иначе
   
// для других способов подключения алгоритм не актуален
   
Возврат;
КонецЕсли;

 

Для работы с агентом сервера необходимо использовать COM-объект

 

Коннектор = Новый COMОбъект("v82.COMConnector");

 

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

 

Агент = Коннектор.ConnectAgent(ИмяСервера);

Теперь перебираем все кластеры, в которых учавствует агент:

 

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

 

Чтобы получить доступ к процессам кластера, необходимо аутентифицироваться, если для кластера задан администратор:

 

АдминистраторКластера = "Имя администратора кластера";
ПарольКластера = "Пароль администратора кластера";
Агент.Authenticate(Кластер, АдминистраторКластера, ПарольКластера);

 

если кластер без ограничения доступа, то следует писать так:

 

Агент.Authenticate(Кластер, , );

 

Теперь необходимо получить перечень процессов, которые обрабатывают данный кластер:

 

Процессы = Агент.GetWorkingProcesses(Кластер);
    Для каждого
Процесс из Процессы Цикл

 

Т.к. к рабочему процессу необходимо подключаться через коннектор, то необходимо вычислить порт, на котором работает данный процесс:

 

Порт = Процесс.MainPort;
// теперь есть адрес и порт для подключения к рабочему процессу
РабПроц = Коннектор.ConnectWorkingProcess(ИмяСервера + ":" + СтрЗаменить(Порт, Символы.НПП, ""));

 

Рабочий процесс необходимо для разрыва соединений. Разрыв сессий происходит через агента. Опишем подробно. Сначала необходимо аутентифицироваться в рабочем процесс по имени и паролю пользователя, у которого в базе данных есть право "Администратор":

 

РабПроц.AddAuthentication("Имя администратора БД", "Пароль администратора БД");

 

На этом этапе есть объект агента и рабочего процесса, который обслуживает текущий кластер. Далее необходимо найти искомую базу данных:

 

ИнформационнаяБаза = "";

Базы = Агент.GetInfoBases(Кластер);
Для каждого
База из Базы Цикл
    Если
База.Name = ИмяБазы Тогда
       
ИнформационнаяБаза = База;
        Прервать;
    КонецЕсли;
КонецЦикла;
Если
ИнформационнаяБаза = "" Тогда
   
// база не найдена
КонецЕсли;

 

Отключение сеансов

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

 

Сеансы = Агент.GetInfoBaseSessions(Кластер, ИнформационнаяБаза);
Для каждого
Сеанс из Сеансы Цикл
    Если
нРег(Сеанс.AppID) = "backgroundjob" ИЛИ нРег(Сеанс.AppID) = "designer" Тогда
       
// если это сеансы конфигуратора или фонового задания, то не отключаем
       
Продолжить;
    КонецЕсли;
    Если
Сеанс.UserName = ИмяПользователя() Тогда
       
// это текущий пользователь
       
Продолжить;
    КонецЕсли;
   
Агент.TerminateSession(Кластер, Сеанс);
КонецЦикла;

 

Также у типа "Сеанс" есть ещё много разных свойств, например, имя компьютера, данные о языке, времени и длительности подключения и тп.

Отключение соединений

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

 

СоединенияБазы = Агент.GetInfoBaseConnections(Кластер, ИнформационнаяБаза);
// Разорвать соединения клиентских приложений.
Для Каждого Соединение Из СоединенияБазы Цикл
    Если
нРег(Соединение.Application) = "backgroundjob" ИЛИ нРег(Соединение.Application) = "designer" Тогда
       
// если это соединение конфигуратора или фонового задания, то не отключаем
       
Продолжить;
    КонецЕсли;
    Если
Соединение.UserName = ИмяПользователя() Тогда
       
// это текущий пользователь
       
Продолжить;
    КонецЕсли;
   
РабПроц.Disconnect(Соединение);
КонецЦикла;

Выводы

Получен пример отключения сеансов и соединений с информационной базы. При должном знании  свойств каждого типа  (рабочий процесс, агент сервера, сеанс, соединение) можно, например, сделать откючение конкретного пользователя по расписанию (однако, совершенно другой вопрос зачем это делать) либо, используя данные конструкции, написать внешнее приложение, которое будет использовать COM-объект "v82.COMConnector".

 

P.S.

Для понимающих работу с этими типами: код намеренно раздут, для того, чтобы под отладчиком было удобнее просматривать значения всех типов. Да, некоторые места можно написать короче и элегантнее, однако цель была в наглядности кода.

 

Код целиком

Если Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr") > 0 Тогда
   
// серверный вариант
   
Поиск1 = Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr=");
   
ПодстрокаПоиска = Сред(СтрокаСоединенияИнформационнойБазы(), Поиск1 + 6);
   
ИмяСервера = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1);
   
// теперь ищем имя базы
   
Поиск1 = Найти(СтрокаСоединенияИнформационнойБазы(), "Ref=");
   
ПодстрокаПоиска = Сред(СтрокаСоединенияИнформационнойБазы(), Поиск1 + 5);
   
ИмяБазы = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1);
Иначе
   
// для других способов подключения алгоритм не актуален
   
Возврат;
КонецЕсли;

Коннектор = Новый COMОбъект("v82.COMConnector");
Агент = Коннектор.ConnectAgent(ИмяСервера);
Кластеры = Агент.GetClusters();
Для каждого
Кластер из Кластеры Цикл
   
АдминистраторКластера = "Имя администратора кластера";
   
ПарольКластера = "Пароль администратора кластера";
   
Агент.Authenticate(Кластер, АдминистраторКластера, ПарольКластера);
   
Процессы = Агент.GetWorkingProcesses(Кластер);
    Для каждого
Процесс из Процессы Цикл
       
Порт = Процесс.MainPort;
       
// теперь есть адрес и порт для подключения к рабочему процессу
       
РабПроц = Коннектор.ConnectWorkingProcess(Имяервера + ":" + СтрЗаменить(Порт, Символы.НПП, ""));
       
РабПроц.AddAuthentication("Имя администратора БД", "Пароль администратора БД");

       
ИнформационнаяБаза = "";

       
Базы = Агент.GetInfoBases(Кластер);
        Для каждого
База из Базы Цикл
            Если
База.Name = ИмяБазы Тогда
               
ИнформационнаяБаза = База;
                Прервать;
            КонецЕсли;
        КонецЦикла;
        Если
ИнформационнаяБаза = "" Тогда
           
// база не найдена
       
КонецЕсли;

       
Сеансы = Агент.GetInfoBaseSessions(Кластер, ИнформационнаяБаза);
        Для каждого
Сеанс из Сеансы Цикл
            Если
нРег(Сеанс.AppID) = "backgroundjob" ИЛИ нРег(Сеанс.AppID) = "designer" Тогда
               
// если это сеансы конфигуратора или фонового задания, то не отключаем
               
Продолжить;
            КонецЕсли;
            Если
Сеанс.UserName = ИмяПользователя() Тогда
               
// это текущий пользователь
               
Продолжить;
            КонецЕсли;
           
Агент.TerminateSession(Кластер, Сеанс);
        КонецЦикла;

       
СоединенияБазы = Агент.GetInfoBaseConnections(Кластер, ИнформационнаяБаза);
       
// Разорвать соединения клиентских приложений.
       
Для Каждого Соединение Из СоединенияБазы Цикл
            Если
нРег(Соединение.Application) = "backgroundjob" ИЛИ нРег(Соединение.Application) = "designer" Тогда
               
// если это соединение конфигуратора или фонового задания, то не отключаем
               
Продолжить;
            КонецЕсли;
            Если
Соединение.UserName = ИмяПользователя() Тогда
               
// это текущий пользователь
               
Продолжить;
            КонецЕсли;
           
РабПроц.Disconnect(Соединение);
        КонецЦикла;
    КонецЦикла;
КонецЦикла;

 

См. также

PowerTools от 1 000
Подписаться Добавить вознаграждение

Комментарии

1. VVV (V_V_V) 04.11.10 17:37
Спасибо, то что нужно.
Но есть пару непоняток (для меня):
я заменил "Сервер" на "ИмяСервера" в строке
РабПроц = Коннектор.ConnectWorkingProcess(Сервер + ":" + СтрЗаменить(Порт, Символы.НПП, ""));
и в COMОбъекте Соединение нет значения UserName, т.е. не могу проверить на ИмяПользователя(). Но и в Сеанс, и в Соединение есть SessionID, пришлось выкручиваться через него (получать в Сеанс и проверять в Соединение). UserName только у меня отсутствует? Платформа 8.2.11.236.
2. VVV (V_V_V) 04.11.10 18:19
По синтакс-помощнику GetInfoBaseConnections получает массив описаний соединений информационной базы. А в описании соединения нет свойства UserName. Оно есть в свойствах соединения.
Осталось только разобраться как получить не описание соединений, а сами соединения... :D
3. VVV (V_V_V) 04.11.10 21:05
Хм... Соединения заработали только когда прописал (обгуглившись по самое ну погоди):

ИнформационнаяБаза2 = РабПроц.CreateInfoBaseInfo();
ИнформационнаяБаза2.Name = ИмяБазы;
Соединения = РабПроц.GetInfoBaseConnections(ИнформационнаяБаза2);

При этом проверять запущенные приложения нужно не по Соединение.Application, а по Соединение.AppID. Плюс не мешало бы добавить проверку не только backgroundjob, designer, а и comconsole - а то выкинет и только что аутентифицированное COM-соединение...
Все вышесказанное абсолютно не претендует на истину - пробуйте на свой страх и риск... :D
4. Asdam (Asdam) 05.11.10 09:18
Rabajaba, поделитесь, плиз, модулем регламентного задания, отвечающего за резервное копирование.
5. Rabajaba Caspersky (Rabajaba) 05.11.10 10:42
(3) Спасибо за развитие, честно дальше не копал. По "Сервер" на "ИмяСервера" - это я код не подправил :)
"Плюс не мешало бы добавить проверку не только backgroundjob, designer, а и comconsole - а то выкинет и только что аутентифицированное COM-соединение... " я показал лишь пример, дальше можно расширять как угодно :) моей целью было НЕ убивать текущее фоновое задание и НЕ закрывать конфигуратор, в котором я могу что-то не сохранить :) да и вообще сама идея мочить конфигуратор - ужас.

(4) Модуль довольно специфичен, но суть проста. Объясню на примере:
01:00 запуск регламетного задания, которое генерирует *.bat файл пакетного запуска конфигуратора в режиме выгрузки ИБ, после чего мочит все соединения
01:20 регламентное задание винды стартует *.bat файл.
Поделиться можно, но там код весь на константах и не очень красив, чтобы на люди показывать :)
6. sound sound (sound) 11.11.10 10:48
Материал нужный однозначно, особенно для конкретных заточек (мало ли кому что надо). А вот про скрипты для бекапов уже можно оды слагать, причем хоть на 1C хоть на VBS, вот например есть http://infostart.ru/public/19363/, там кстати любезно расписаны все обработки аналогичной направленности - бери нихачу :)
7. Артур Антипин (artur.antipin) 11.10.11 14:16
Платформа 8.2.14.519, режим серверный.
При подключении к Агенту выдает такую ошибку:
{Форма.Форма.Форма(108)}: Ошибка при вызове метода контекста (ConnectAgent)
СлужбаСервера = Соединитель.ConnectAgent(СерверБД);
по причине:
Произошла исключительная ситуация (V82.COMConnector.1): descr=Сервер недоступен (Не отвечает, завершается аварийно или порт занят другим приложением) line=556 file=Src\RemoteCreatorImpl.cpp
Кто нибудь с такой сталкивался?
8. Владимир Бегунов (VchikA) 14.11.11 11:55
(7) столкнулся с такой ошибкой. Дело в том, что строка подключения к базе данных содержало порт. Таким образом при получении имени сервера, возвращается не имя сервера("127.0.0.1"), а имя сервера + порт ("127.0.0.1:1689").
Заменил строку - все заработало:
//ИмяСервера = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1); //для стандартного порта (1541)
ИмяСервера = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 6); //для не стандартного порта (7) artur.antipin,
9. alexbur (alexbur) 30.11.11 07:03
(3) V_V_V, Всё верно. Тоже дошёл до этого обчитавшись хелпа. Дело в том, что если делать GetInfoBaseConnections через агента сервера (а не через рабочий процесс), то мы получаем на выходе тип "Описание соединения", а не "Соединение". У него действительно нет UserName и вместо AppID есть Applications.

Если Соединение.UserName = ИмяПользователя() Тогда
// это текущий пользователь
Продолжить;
КонецЕсли;


ИМХО, чтобы не убить своё собственное соединение лучше использовать проверку на SessionID (ConnID), который есть и в соединении (сеансе). Получить SessionID (ConnID) текущего (своего) подключения можно через НомерСеансаИнформационнойБазы() (НомерСоединенияИнформационнойБазы()).
a--jey; PhoenixAOD; bashirov.rs; tradeagent; eeeio; +5 Ответить 1
10. VVV (V_V_V) 30.11.11 20:29
(9) Если ничего не путаю, то именно через SessionID я и выкрутился. Кажется об этом речь в моем первом посте шла (1).
Как давно это было... Год прошел... :)
11. alexbur (alexbur) 01.12.11 07:40
(10) V_V_V, Ну, некоторые темы не стареют. Для меня как раз проблемой было как раз узнать ID текущего сеанса, чтобы сравнить с SesionID. Может кому нибудь тоже поможет.
12. Алекс Ос (ekean) 23.12.11 12:18
Вместо -
РабПроц = Коннектор.ConnectWorkingProcess(Имяервера + ":" + СтрЗаменить(Порт, Символы.НПП, ""));
надо -
РабПроц = Коннектор.ConnectWorkingProcess("tcp://" + Процесс.HostName + ":" + Формат(Процесс.MainPort, "ЧГ=0"));
13. Михаил Леонтьев (mike24) 13.01.12 14:59
Автору - спасибо! Использовал для отключения юзеров при ночной выгрузке базы
вот обобщенный (рабочий!) вариант:

Если Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr") > 0 Тогда
// серверный вариант
Поиск1 = Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr=");
ПодстрокаПоиска = Сред(СтрокаСоединенияИнформационнойБазы(), Поиск1 + 6);
ИмяСервера = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1);
// теперь ищем имя базы
Поиск1 = Найти(СтрокаСоединенияИнформационнойБазы(), "Ref=");
ПодстрокаПоиска = Сред(СтрокаСоединенияИнформационнойБазы(), Поиск1 + 5);
ИмяБазы = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1);
Иначе
// для других способов подключения алгоритм не актуален
Возврат;
КонецЕсли;

Коннектор = Новый COMОбъект("v82.COMConnector");
Агент = Коннектор.ConnectAgent(ИмяСервера);
Кластеры = Агент.GetClusters();
Для каждого Кластер из Кластеры Цикл
АдминистраторКластера = "Имя администратора кластера";
ПарольКластера = "Пароль администратора кластера";
//Агент.Authenticate(Кластер, АдминистраторКластера, ПарольКластера);
Агент.Authenticate(Кластер,,);
Процессы = Агент.GetWorkingProcesses(Кластер);
Для каждого Процесс из Процессы Цикл
Порт = Процесс.MainPort;
// теперь есть адрес и порт для подключения к рабочему процессу
РабПроц = Коннектор.ConnectWorkingProcess(ИмяСервера + ":" + СтрЗаменить(Порт, Символы.НПП, ""));
РабПроц.AddAuthentication("admin", "pass");

ИнформационнаяБаза = "";

Базы = Агент.GetInfoBases(Кластер);
Для каждого База из Базы Цикл
Если База.Name = ИмяБазы Тогда
ИнформационнаяБаза = База;
Прервать;
КонецЕсли;
КонецЦикла;
Если ИнформационнаяБаза = "" Тогда
// база не найдена
КонецЕсли;

Сеансы = Агент.GetInfoBaseSessions(Кластер, ИнформационнаяБаза);
Для каждого Сеанс из Сеансы Цикл

Если нРег(Сеанс.AppID) = "backgroundjob" ИЛИ нРег(Сеанс.AppID) = "comconsole" Тогда
// если это сеансы com-приложения или фонового задания, то не отключаем
Продолжить;
КонецЕсли;
Если Сеанс.UserName = ИмяПользователя() Тогда
// это текущий пользователь
Продолжить;
КонецЕсли;
Агент.TerminateSession(Кластер, Сеанс);
Сообщить("Отключен сеанс "+строка(Сеанс.UserName));
КонецЦикла;

ИнформационнаяБаза2 = РабПроц.CreateInfoBaseInfo();
ИнформационнаяБаза2.Name = ИмяБазы;
СоединенияБазы = РабПроц.GetInfoBaseConnections(ИнформационнаяБаза2);
// Разорвать соединения клиентских приложений.
Для Каждого Соединение Из СоединенияБазы Цикл
Если нРег(Соединение.AppID) = "backgroundjob" ИЛИ нРег(Соединение.AppID) = "comconsole" Тогда
Продолжить;
КонецЕсли;
Если Соединение.UserName = ИмяПользователя() Тогда
// это текущий пользователь
Продолжить;
КонецЕсли;
РабПроц.Disconnect(Соединение);
КонецЦикла;
КонецЦикла;
КонецЦикла;
Предупреждение("Завершается работа...", 5);
ЗавершитьРаботуСистемы(Ложь);


запускаю из батника
C:\"Program Files"\1cv82\8.2.13.219\bin\1cv8.exe ENTERPRISE /sИмяСервера\ИмяБазы /nПользователь /pПароль /wa- /DisableStartupMessages /RunModeOrdinaryApplication /ExecuteShutdownusers.epf

Shutdownusers.epf - в этой внешней обработке код
OVANGE; Krick777; PhoenixAOD; ColaKola; bashirov.rs; b-dm; tradeagent; XoloD; eeeio; +9 Ответить
14. Den (Dvornik) 01.02.12 07:35
В платформе 8.2.14 работает? Никто не подскажет?
15. Эдуард (edyardg) 06.02.12 15:12
Спасибо очень нужная информация
16. Марина Ксен (Marichka2) 06.02.12 16:08
Спасибо очень нужная информация, попробую у себя
17. Игорь Зуйков (quares) 15.02.12 16:31
Интересно и полезно - да. Но схема алгоритма (если читать код описанный выше) не совсем соответствует коду.
Автору 5 баллов.
18. Леонид Лесин (Leoway) 11.03.12 18:03
Огромное спасибо, очень помогло.
19. Андрей Мирошниченко (deshi2) 06.04.12 17:33
спасибо, безгранично полезный код!
20. Андрей Мирошниченко (deshi2) 06.04.12 17:49
кстати, рекомендую на совпадение с текущей базой проверять с учетом регистра, уже нарвался. Вот так надо:

Если ВРЕГ(База.Name) = ВРЕГ(ИмяБазы) Тогда
ИнформационнаяБаза = База;
Прервать;
КонецЕсли;
succub1_5; PhoenixAOD; tradeagent; XoloD; eeeio; +5 Ответить
21. sad sad (sad12345) 09.07.12 13:32
8.2.15.301
Соединение.UserName = ИмяПользователя()
ERROR:
Поле объекта не обнаружено (UserName)

FAQ:
Соединение (IInfoBaseConnectionInfo)
UserName (UserName)
Использование:

Только чтение.
Описание:

Тип: Строка.
Содержит имя пользователя 1С:Предприятия, подсоединенного к информационной базе.

Доступность:

Интеграция.

Что не так???
22. вирус 1с (virus-1c) 24.07.12 11:20
(21) sad12345,
У меня такая же проблема

сделал так
ТекПользовательApplication = "";
ТекПользовательConnId = "";
ТекПользовательHost = "";

Сеансы = Агент.GetInfoBaseSessions(Кластер, ИнформационнаяБаза);
Для каждого Сеанс из Сеансы Цикл
Если нРег(Сеанс.AppID) = "backgroundjob" ИЛИ нРег(Сеанс.AppID) = "designer" Тогда
// если это сеансы конфигуратора или фонового задания, то не отключаем
Продолжить;
КонецЕсли;
Если Сеанс.UserName = ИмяПользователя() Тогда
// это текущий пользователь
ТекПользовательApplication = Сеанс.Connection.Application;
ТекПользовательConnId = Сеанс.Connection.ConnId;
ТекПользовательHost = Сеанс.Connection.Host;
Продолжить;
КонецЕсли;
Агент.TerminateSession(Кластер, Сеанс);
Сообщить(строка(Сеанс.UserName) + " - " + нРег(Сеанс.AppID));
КонецЦикла;

СоединенияБазы = Агент.GetInfoBaseConnections(Кластер, ИнформационнаяБаза);
// Разорвать соединения клиентских приложений.
Для Каждого Соединение Из СоединенияБазы Цикл
Если нРег(Соединение.Application) = "backgroundjob" ИЛИ нРег(Соединение.Application) = "designer" Тогда
// если это соединение конфигуратора или фонового задания, то не отключаем
Продолжить;
КонецЕсли;
//Если Соединение.UserName = ИмяПользователя() Тогда
// // это текущий пользователь
// Продолжить;
//КонецЕсли;
Если (Соединение.Application = ТекПользовательApplication) и (Соединение.ConnId = ТекПользовательConnId) и (Соединение.Host = ТекПользовательHost) Тогда
// это текущий пользователь
Продолжить;
КонецЕсли;

РабПроц.Disconnect(Соединение);
КонецЦикла;
23. Oleg Moskvichev (m_aster) 04.08.12 00:04
24. Stamper (Stamper) 07.09.12 11:22
шикарно! благодарю
был у меня еще "отключатель" от файловой базы "ProcessKiller" на vbs, но потерялся :(
никто не встречал?
25. Stepan Shipitsyn (Stepan_1c) 23.11.12 05:28
Спасибо. раньше почему то не нашел и написал свой вариант через батник. сейчас попробую через 1с :)
26. andrey dyak (dyak84) 20.03.13 19:06
Автору огромное спасибо. Написано просто и доступно. Надоело бесконечно тестировать чужую работу пора и самому разбиратся как и что работает в 1С. Побольше бы таких статей. Протестирую и отпишусь
27. Дмитрий Балачий (dmbal) 24.03.13 20:00
Платформа 1С:Предприятие 8.2 (8.2.17.153).

РабПроц.Disconnect(Соединение);
по причине:
Типы не совпадают (1)

Как не пробовал, одно и тоже :(

Вариант кода следующий:

Для Каждого Соединение Из СоединенияБазы Цикл
Если нРег(Соединение.Application) = "backgroundjob" ИЛИ нРег(Соединение.Application) = "designer" Тогда
// если это соединение конфигуратора или фонового задания, то не отключаем
Продолжить;
КонецЕсли;
//Если Соединение.UserName = ИмяПользователя() Тогда
// // это текущий пользователь
// Продолжить;
//КонецЕсли;
Если (Соединение.Application = ТекПользовательApplication) и (Соединение.ConnId = ТекПользовательConnId) и (Соединение.Host = ТекПользовательHost) Тогда
// это текущий пользователь
Продолжить;
КонецЕсли;

РабПроц.Disconnect(Соединение);

КонецЦикла;
28. Andrey Semenov (aprol) 16.05.13 09:35
(27) dmbal, Та же ситуация на платформе 15.319, решения не нашел.
29. Юрий Фенский (griffer) 21.05.13 12:21
Спасибо автору!
Внес небольшие изменения и использовал для закрытия сеансов и соединений оставшихся после аварийного завершения работы.
30. Stamper (Stamper) 21.05.13 16:38
(29) griffer, выкладывайте, чего уж там :)
31. Юрий Фенский (griffer) 29.05.13 14:30
(30) Stamper, не жалко - выкладываю)
В таком варианте не возникает ошибка
Типы не совпадают (1)


Если Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr") > 0 Тогда
		// серверный вариант
		Поиск1 = Найти(СтрокаСоединенияИнформационнойБазы(), "Srvr=");
		ПодстрокаПоиска = Сред(СтрокаСоединенияИнформационнойБазы(), Поиск1 + 6);
		ИмяСервера = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1);
		// теперь ищем имя базы
		Поиск1 = Найти(СтрокаСоединенияИнформационнойБазы(), "Ref=");
		ПодстрокаПоиска = Сред(СтрокаСоединенияИнформационнойБазы(), Поиск1 + 5);
		ИмяБазы = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1);
	Иначе
		// для других способов подключения алгоритм не актуален
		Возврат;
	КонецЕсли;
	
	Коннектор = Новый COMОбъект("v82.COMConnector");
	Агент = Коннектор.ConnectAgent(ИмяСервера);
	Кластеры = Агент.GetClusters();
	
	Для ТекущийИндекс = Кластеры.GetLowerBound() По Кластеры.GetUpperBound() Цикл
		// Ищем нужный нам кластер
		Кластер = Кластеры.GetValue(ТекущийИндекс);
		Если (ВРЕГ(Кластер.HostName) = ИмяСервера) Тогда 
			Прервать; 
		КонецЕсли
	КонецЦикла;
	
	Если Кластер = НЕОПРЕДЕЛЕНО Тогда
		Сообщить("Не удалось определить рабочий кластер серверов 1С предприятия", СтатусСообщения.Важное);
		Возврат;
	КонецЕсли;
	
	Агент.Authenticate(Кластер, , );
	
	РабочиеСервера = Агент.GetWorkingServers(Кластер);
	Для Каждого РабочийСервер Из РабочиеСервера Цикл
		РабочиеПроцессы = Агент.GetServerWorkingProcesses(Кластер, РабочийСервер);
		Если РабочиеПроцессы <> НЕОПРЕДЕЛЕНО Тогда
			Для Каждого Процесс Из РабочиеПроцессы Цикл
				Если Процесс.Running <> 1 Тогда
					Продолжить; //Не тратим время на неработающие процессы 
				КонецЕсли;
				ЕстьРегПроцесса  = Ложь;
				СтрокаСоединения = "TCP://" + Процесс.HostName+":"+XMLСтрока(Процесс.MainPort);
				РабПроц = Коннектор.ConnectWorkingProcess(СтрокаСоединения);
				Если РабПроц <> Неопределено Тогда
					Базы = РабПроц.GetInfoBases();
					Если Базы  <> НЕОПРЕДЕЛЕНО Тогда
						Для Каждого База ИЗ Базы Цикл
							// Ищем нашу базу
							Если База.Name <> ИмяБазы Тогда
								Продолжить;
							КонецЕсли;
							// Восстановим админское подключение к базе (в случае ошибки и при переходе на другой рабочий процесс)
							Если НЕ ЕстьРегПроцесса Тогда
								Попытка
									РабПроц.AddAuthentication(ИмяАдминистратора, ПарольАдминистратора);
									ЕстьРегПроцесса=Истина;
								Исключение
									Сообщить(ОписаниеОшибки(), СтатусСообщения.Важное);
								КонецПопытки;
							КонецЕсли;
							// Получим и обойдем все соединения с нашей базой в текущем рабочем процессе
							СоединенияБазы = РабПроц.GetInfoBaseConnections(База);
							Если СоединенияБазы <> НЕОПРЕДЕЛЕНО Тогда
								Для Каждого Соединение Из СоединенияБазы Цикл
									UserName = Соединение.UserName;
									ConnID	 = Соединение.ConnID;
									AppID    = НРег(Соединение.AppID);
									
									Если AppID = "backgroundjob" ИЛИ AppID = "designer" ИЛИ AppID = "comconsole" Тогда
										// если это соединение конфигуратора, фонового задания или наше COM-соединение или  то не отключаем
										Продолжить;
									КонецЕсли;
									
									Попытка
										Если UserName = ИмяПользователя() И ConnID <> НомерСоединенияИнформационнойБазы() Тогда
											Сообщить("Отключено соединение: " + "User=["+UserName+"] ConnID=["+ConnID+"] AppID=["+AppID+"]", СтатусСообщения.Важное);
											РабПроц.Disconnect(Соединение);
										КонецЕсли; 
									Исключение
										ЕстьРегПроцесса=Ложь;
									КонецПопытки;
								КонецЦикла; // По соединениям
								Соединение 			= НЕОПРЕДЕЛЕНО;
								СоединенияБазы 		= НЕОПРЕДЕЛЕНО;
							КонецЕсли;
						КонецЦикла; // По базам
						База				= НЕОПРЕДЕЛЕНО;
						Базы 				= НЕОПРЕДЕЛЕНО;
					КонецЕсли;
				КонецЕсли;
			КонецЦикла; // по рабочим процессам
		КонецЕсли;
		РабПроц					= НЕОПРЕДЕЛЕНО;
		Процесс					= НЕОПРЕДЕЛЕНО;
		РабочиеПроцессы			= НЕОПРЕДЕЛЕНО;
	КонецЦикла; // по серверам
...Показать Скрыть
32. vers139 (vers139) 19.09.13 12:14
Интересно, что если пытаться разорвать соединения перед завершением сеансов, то 1С выдаёт ошибку при попытке получить сеансов. Ругается на несоответствие типов в методе GetInfoBaseSessions. Поменял местами куски кода (сначала сеансы, потом соединения) и всё заработало.
33. poyson (poyson) 07.05.14 09:14
34. Александр Жарков (miller-adm) 04.09.14 02:49
35. Андрей Герасимов (gerandy) 26.06.15 17:18
Спасибо, очень полезный код!

Строчку в коде griffer
Если UserName = ИмяПользователя() И ConnID <> НомерСоединенияИнформационнойБазы() Тогда


исправил
UserName <> ИмяПользователя()
36. Андрей Франчук (aspiid) 10.09.15 18:12
(8) VchikA,
Тоже столкнулся с этой проблемой.
Заменил строку - все заработало:
//ИмяСервера = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 1); //для стандартного порта (1541)
ИмяСервера = Лев(ПодстрокаПоиска, Найти(ПодстрокаПоиска, """") - 6); //для не стандартного порта (7) artur.antipin,

Вот не уверен, что это правильно.
Вообще говоря, то ИмяСервера (включая порт), которое мы получаем таким образом, это адрес кластера 1с, на котором крутится эта база. Если порт стандартный, то он совпадает с именем сервера (читай агента сервера). Если порты не стандартные - то они разные.
Так вот. Если вы просто обрежете порт из адреса кластера, то получите обращение по стандартному порту, т.е. 1541, и скорее всего, попадете на другой сервер, не тот, на котором крутится данная база.
Вот в связи с этим вопрос: можно ли как то узнать полный адрес агента сервера, на котором крутится эта база?
37. Полищук Анатолий (tolstoy) 23.09.15 14:59
Спасибо автору!
От себя добавлю: если администратор кластера не указан, то аутентификацию к агенту сервера нужно осуществлять кодом:
АгентСервера.Authenticate(Кластер,"","");

Если подключаться так, как указано в статье
Агент.Authenticate(Кластер,,);

то будет ошибка: "Указанное число параметров не соответствует ожидаемому числу".
38. Владимир Соболев (DrBerg) 01.10.15 12:47
А если мне нужен номер SPID, в СОМ объекте его нет. Каким образом его выудить? Консоль получает этот столбец. Есть идеи?
39. Владимир Соболев (DrBerg) 01.10.15 12:48
(37) tolstoy, Вместо параметров можно передать значения реквизитов формы. Если они пустые и админы не заявлены, то все проходит.
40. Беслан Байрамов (besometr) 09.11.15 14:25
Еще порт может быть не 1540:
мМассивСтрокиСоединения = ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(СтрокаСоединенияИнформационнойБазы(),";");

мСтрокаИБ = мМассивСтрокиСоединения[0];
мСтрокаИБ = СтрЗаменить(мСтрокаИБ,"Srvr=","");
СерверПорт = СтрЗаменить(мСтрокаИБ,"""","");

мМассивСерверПорт = ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(СерверПорт,":");
Если мМассивСерверПорт.Количество() > 1 Тогда
Сервер = мМассивСерверПорт[0];
Порт = СтрЗаменить(Строка(Число(мМассивСерверПорт[1])-1), Символы.НПП, "");
ИначеЕсли мМассивСерверПорт.Количество() = 1 Тогда
Сервер = мМассивСтрокиСоединения[0];
Порт = 1540;
Иначе
Сервер = "localhost";
Порт = 1540;
КонецЕсли;

мСтрокаИБ = мМассивСтрокиСоединения[1];
мСтрокаИБ = СтрЗаменить(мСтрокаИБ,"Ref=","");
База = СтрЗаменить(мСтрокаИБ,"""","");
41. isn Игнатьев (isn) 07.12.15 11:01
В ситуации когда необходимо было отключить пользователей столкнулся с тем что пользователей, которые не успели войти в базу и у которых висит диалог выбора логина и пароля, не отключаются от базы и конфигуратор не обновляется при наличии подключений к базе.
42. Юрий (yuraer) 15.08.16 15:34
А кто-нибудь пробовал отключать зависшие регламентные задания таким способом?
Чем чревато такое отключение, если оно возможно?
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа