gifts2017

Уникальность и борьба с висящими сеансами БД 1С

Опубликовал Alex Nikitin (nikitin19819) в раздел Администрирование - Системное

Если возникла ситуация, что произошел несанкционированный сбой в сети и после перезагрузки остается на  висеть сеанс (хотя на самом деле пользователь
не подключен и сеанс неактивен), то появится диалоговое окно с запросом отключить или нет предыдущий сеанс.
//!!! Для обычного приложения версии 8.2
//Размещать код следует в начало Процедуры ПриНачалеРаботыСистемы модуля обычного приложения.
//Принцип работы - Если возникла ситуация, что произошел несанкционированный сбой в сети и после перезагрузки остается на //сервере висеть сеанс (хотя на самом деле пользователь
//не подключен и сеанс неактивен), то появится диалоговое окно с запросом отключить или нет предыдущий сеанс.
//ПО ПРОСЬБЕ вставлю фрагмент, кот-ый автоматически определит Имя БД, ИмяСервера //********** СтрокаСоединения = СтрокаСоединенияИнформационнойБазы(); Если СтрЧислоВхождений(ВРег(СтрокаСоединения), "FILE=") Тогда Возврат; КонецЕсли; СтрДлина = СтрДлина(СтрокаСоединения); // Ищем имя сервера СтрокаСервера = ВыделитьПодстрокуСтрокиЗапуска(СтрокаСоединения, "Srvr="); ИмяБД = ВыделитьПодстрокуСтрокиЗапуска(СтрокаСоединения, "Ref="); // Если в имени сервера присутствует имя порта, то выделяем его РазделительПорта = Найти(СтрокаСервера, ":"); Если РазделительПорта > 0 Тогда ИмяСервера = Сред(СтрокаСервера, 1, (РазделительПорта - 1)); НомерПортаКластера = Сред(СтрокаСервера, (РазделительПорта + 1)); Иначе ИмяСервера = СтрокаСервера; ком = Новый COMОбъект("v81.COMConnector"); НомерПортаКластера = ком.RMngrPortDefault; КонецЕсли; //*******
ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
ПризнакСеанса = 0;
//для обеспечения невозможности повторного входа пользователя, который уже присутствует в БД
//что делается:
ТекущийНомерСоединения=НомерСоединенияИнформационнойБазы();
УникальныйИдентификаторПользователя=ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
ТекущееСоединениеИмяКомпьютера = ИмяКомпьютера();
ServerName = ИмяСервера; //Имя Вашего сервера 1С
connector = новый comОбъект("V82.COMConnector");
AgentConnection = Connector.ConnectAgent(ServerName);
МассивКластеров = AgentConnection.GetClusters();
//определяем кластёр как описание типов
Для каждого Кластер ИЗ МассивКластеров Цикл
Если (Кластер.HostName = ИмяСервера) и (Кластер.SyncPort=НомерПортаКластера) тогда КластерТекущейБД = Кластер; //Думаю, что имя сервера будет совпадать с именем компа :)
   // Сообщить(Кластер.HostName);
КонецЕсли;
Прервать;
КонецЦикла;
//Доступ на просмотр сеансов
AgentConnection.Authenticate(КластерТекущейБД,"Администратор","Пароль");
//Для получения ВСЕХ тек.сеансов для данной БД - для инфо.. потом закомм и заодно БД как описание типов
МассивСеансов = AgentConnection.GetSessions(КластерТекущейБД);    
Для каждого Сеанс ИЗ МассивСеансов Цикл
Если (Сеанс.Infobase.Name = ИмяБД) и (Сеанс.UserName = ПользователиИнформационнойБазы.ТекущийПользователь().Имя) тогда
     ОписаниеБД = Сеанс.Infobase;
КонецЕсли;
КонецЦикла;
// Для случаев с висящими сеансами
МассивВсехСессийБД = AgentConnection.GetInfoBaseSessions(КластерТекущейБД,ОписаниеБД);   
Для каждого СессияБД ИЗ МассивВсехСессийБД Цикл
Если //(СессияБД.Host = ТекущееСоединениеИмяКомпьютера) И //ЭТО ЕСЛИ НАДО ИНИЦИАЛИЗАЦИЯ ПО КОМПУ
     (СессияБД.UserName = ПользователиИнформационнойБазы.ТекущийПользователь().Имя) И
     (СессияБД.Connection.Application = "1CV8")
тогда
       Если СессияБД.Connection.ConnID <> ТекущийНомерСоединения
       тогда
Режим = РежимДиалогаВопрос.ДаНет;
           Текст = "Сеанс данного пользователя активен! " + СессияБД.UserName +
                    "| Закрыть предыдущий сеанс? При сбое в сети нажмите <<Да>>";
           Ответ = Вопрос(Текст,Режим,0);
            Если Ответ = КодВозвратаДиалога.Да тогда
                AgentConnection.TerminateSession(КластерТекущейБД,СессияБД);
           КонецЕсли;
           Если Ответ = КодВозвратаДиалога.Нет тогда
         ПризнакСеанса = 1;
    Предупреждение("Внимание! Активно несколько сеансов для одного пользователя");
   КонецЕсли;
      КонецЕсли;
    //если просто висяк,тада безоговорочно закроет на серваке висячий сеанс. проверить
  Сообщить("НомерСоединения: " + СессияБД.Connection.ConnID + " Номер сеанса: " + СессияБД.SessionID);//Сеансы
КонецЕсли;
КонецЦикла;
//а если с другого компа под этим ползуном, ЗАКРЫВАТЬ БУДЕТ ГОСТЯ
//Этот фрагмент кода можно не включать, если Вам нужно просто закрыть висящий сеанс.
МассивСоединений=ПолучитьСоединенияИнформационнойБазы();
Для Каждого ТекСоединение Из МассивСоединений Цикл
Сообщить(ТекСоединение.НомерСоединения);
Если (ТекСоединение.ИмяПриложения="1CV8")                
и(НЕ ТекСоединение.НомерСоединения=ТекущийНомерСоединения)
и(НЕ ТекСоединение.Пользователь=неопределено)        
и(ТекСоединение.Пользователь.УникальныйИдентификатор=УникальныйИдентификаторПользователя)
и(ПризнакСеанса = 0)
//и(НЕ СессияБД.Host = ТекущееСоединениеИмяКомпьютера)
//и(ТекСоединение.Пользователь.ИмяКомпьютера = ТекущееСоединениеИмяКомпьютера)
тогда
   Предупреждение("Пользователь с таким именем уже выполнил вход ! Имя ПК >> " + СессияБД.Host);
        ЗавершитьРаботуСистемы(Ложь);
КонецЕсли;   
КонецЦикла;       
По просьбе - И еще добавить в Модуль новую функцию
// Функция выделяет необходимые части из строки запуска 
// 
Функция ВыделитьПодстрокуСтрокиЗапуска(СтрокаЗапуска, КлючПодстроки) Экспорт 
НомерПервогоСимвола = Найти(ВРег(СтрокаЗапуска), ВРег(КлючПодстроки)) + СтрДлина(КлючПодстроки); 
Для Счетчик = НомерПервогоСимвола По СтрДлина(СтрокаЗапуска) Цикл 
   Если Сред(СтрокаЗапуска, Счетчик, 1) = ";" Тогда 
       НомерПоследнегоСимвола = Счетчик - 1; 
       Прервать; 
   КонецЕсли; 
КонецЦикла; 
// Получаем искомую подстроку 
ИскомаяПодстрока = Сред(СтрокаЗапуска, НомерПервогоСимвола, (НомерПоследнегоСимвола - НомерПервогоСимвола + 1)); 
Если Сред(ИскомаяПодстрока, 1, 1) = """" Тогда 
// Если подстрока в кавычках, то выделяем их 
ИскомаяПодстрока = Сред(ИскомаяПодстрока, 2, (СтрДлина(ИскомаяПодстрока) - 2)); 
КонецЕсли; 
Возврат ИскомаяПодстрока;

КонецФункции // ВыделитьПодстроку()



См. также

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

Комментарии

1. Гость 11.07.14 15:33
отформатируйте текст статьи
2. Галина Черных (g26516) 16.07.14 08:22
3. Александр Александров (qvvert) 16.07.14 08:58
Получается код вырубает не именно зависший сеанс, а все другие сеансы текущего пользователя
Есть какая то возможность определить простой соединения? Как я видел в консоли - в зависшем соединении - однофигово дата последней активности довольно актуальная ( : Скажем пользователь подвис 1 час назад последняя активность соединения минуту назад
4. asg1981 (nikitin19819) 16.07.14 22:48
Пока только так и получается, что надо зайти еще раз пользователю, чтобы убить пред. сеанс. Вариант есть, если использовать Регламентное задание, которое бы через какой-либо интервал проверяло активность пользователей.
5. soda St (soda) 16.07.14 23:02
А как проверить активность пользователей, если в системе есть что-то связанное с обработкой ожидания. например напоминалка, соотщалка...
6. asg1981 (nikitin19819) 17.07.14 22:39
(1) вася, более-менее навел красоту :)
7. игорь Никик (igo1) 29.07.14 13:58
Спасибо, но еще неплохо бы добавить след код, ну прописать полученные данные где надо

СтрокаСоединения = СтрокаСоединенияИнформационнойБазы();
	Если СтрЧислоВхождений(ВРег(СтрокаСоединения), "FILE=") Тогда
		Возврат;
	КонецЕсли;
		
	СтрДлина = СтрДлина(СтрокаСоединения);
	
	// Ищем имя сервера
	СтрокаСервера = ВыделитьПодстрокуСтрокиЗапуска(СтрокаСоединения, "Srvr=");
	// Если в имени сервера присутствует имя порта, то выделяем его
	РазделительПорта = Найти(СтрокаСервера, ":");
	Если РазделительПорта > 0 Тогда
		ИмяСервера = Сред(СтрокаСервера, 1, (РазделительПорта - 1));
		НомерПортаКластера = Сред(СтрокаСервера, (РазделительПорта + 1));
	Иначе
		ИмяСервера = СтрокаСервера;
		ком = Новый COMОбъект("v81.COMConnector");
		НомерПортаКластера = ком.RMngrPortDefault;
	КонецЕсли; 





// Функция выделяет необходимые части из строки запуска
//
Функция ВыделитьПодстрокуСтрокиЗапуска(СтрокаЗапуска, КлючПодстроки) Экспорт 

	НомерПервогоСимвола = Найти(ВРег(СтрокаЗапуска), ВРег(КлючПодстроки)) + СтрДлина(КлючПодстроки);
	Для Счетчик = НомерПервогоСимвола По СтрДлина(СтрокаЗапуска) Цикл
		Если Сред(СтрокаЗапуска, Счетчик, 1) = ";" Тогда
			НомерПоследнегоСимвола = Счетчик - 1;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	// Получаем искомую подстроку
	ИскомаяПодстрока = Сред(СтрокаЗапуска, НомерПервогоСимвола, (НомерПоследнегоСимвола - НомерПервогоСимвола + 1));
	Если Сред(ИскомаяПодстрока, 1, 1) = """" Тогда
		// Если подстрока в кавычках, то выделяем их
		ИскомаяПодстрока = Сред(ИскомаяПодстрока, 2, (СтрДлина(ИскомаяПодстрока) - 2));
	КонецЕсли;
	
	Возврат ИскомаяПодстрока;

КонецФункции // ВыделитьПодстроку()
...Показать Скрыть
8. asg1981 (nikitin19819) 29.07.14 22:40
(7) igo1, И вам спасибо, я добавил. Но, правда, хотел чтобы код менялся в одном месте. Ну и ладно... Я считаю, что обработка строки - это довольно-таки серьезная штука и полезная. А вообще, Может быть и так, что наш с Вами получившийся код можно оптимизировать. Но в этом виде, думаю, пока подойдет для нетиповых конфиг.
9. JusteR Upra (JusteRU) 30.07.14 02:46
Супер! А нет ли возможности реализации подобного функционала без использования com-объекта, чтобы на linux-сервере использовать по регламентному заданию, например?
Хотя в толстом клиенте запущенном с винды это должно отрабатывать и так, надо попробовать.
10. asg1981 (nikitin19819) 30.07.14 12:09
JusteRU(9), к сожалению, только чуть менее 2х лет в 1С... Как регламентное задание можно сделать. Пробовал на 2003м серваке. Не подошло, потому-что в фоновом режиме иногда выскакивало не в тему сообщение о наличии пользователя в сети. Надо еще немножко переработать для "фона". А насчет Линукса - Ведь ком объект я вызываю чтобы использовать агент-коннектор. Как в обход коннектора все "прокрутить" будет время-разберусь. Счас работу ищу :(
11. Дмитрий Дрейцер (MadDAD) 06.08.14 10:31
(2) g26516, пиарнусь немного. Для 7.7 и для 8.x подойдет мое детище - http://infostart.ru/public/248792/.
12. asg1981 (nikitin19819) 06.08.14 12:35
(11) MadDAD, возьмем на заметку :)
13. Alex Nikitin (nikitin19819) 10.10.15 08:44
хаха. А через Delphi такоя имтерестно реализовано...
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа