Освобождение лицензий. Регламентное задание

Администрирование - Системное

(Разработано для 1С:Документооборот). Доработка решает проблему недостатка лицензий при сравнительно бОльшем количестве активных пользователей. Реализуется путем наблюдения "Протокола работы пользователей" и при отсутствии активности пользователя - отключение его сеанса на сервере. У нас данная доработка включена как рег. задание в 1С:Документооборот. Убиваются все сеансы с неактивностью за последние 30 минут, запускать рег. задание можно соответственно каждые 35 минут.

Суть доработки сводится к тому, что постоянно анализируется ПротоколРаботыПользователей на наличие записей с привязкой к пользователю за последние N-минут.

выбрать * из регистрсведений.протоколработыпользователей где пользователь=&юзер и дата > &датаубийства

При этом список пользователей формируется из выборки активных сеансов 

ПолучитьСеансыИнформационнойБазы()

А дальше из списка на закрытие активного сеанса выкидываются полноправные пользователи, пользователи с сеансом в Конфигураторе и пользователи, поименованные в специальной Роли, у меня для примера она называется "ПользователиНеотключаемыеПоНеактивностиСеанса". Другими словами, если вам надо сделать пользователя, который постоянно может сидеть в приложении и не бояться, что система закроет его сеанс, просто добавьте его в эту роль, это может быть полезно для делопроизводителей, топ-менеджеров.

Дальше происходит отключение сеанса пользователя, находящегося в списке на отключение, делается это с помощью функционала администрирования кластера 1С.

АдминистрированиеКластераКлиентСервер.УдалитьСеансыИнформационнойБазы(ПараметрыАдминистрирования,ПараметрыАдминистрированияИБ, Фильтр);

Для этого вам понадобится две учетных записи: администратор кластера, администратор БД

ПараметрыАдминистрирования = АдминистрированиеКластераКлиентСервер.ПараметрыАдминистрированияКластера(); ПараметрыАдминистрирования.АдресАгентаСервера = "имя_сервера";
ПараметрыАдминистрирования.ПортАгентаСервера = 7540; //по умолчанию в 1С используется 1540
ПараметрыАдминистрирования.ПортКластера = 7541; //по умолчанию в 1С используется 1541
ПараметрыАдминистрирования.ИмяАдминистратораКластера = "имя_администратора_кластера";
ПараметрыАдминистрирования.ПарольАдминистратораКластера = "пароль_администратора_кластера";
ПараметрыАдминистрированияИБ = АдминистрированиеКластераКлиентСервер.ПараметрыАдминистрированияИнформационнойБазыКластера(); ПараметрыАдминистрированияИБ.ИмяВКластере = "имя_базы";
ПараметрыАдминистрированияИБ.ИмяАдминистратораИнформационнойБазы = "имя_администратора_базы"; ПараметрыАдминистрированияИБ.ПарольАдминистратораИнформационнойБазы = "пароль_администратора_базы";

У всей этой доработки есть один несущественный минус - т.к. не все события пишутся в ПротоколРаботыПользователей, то существует ненулевая вероятность, что пользователя "выкинет" даже если он вёл активность в приложении, но процент этих событий мал. 

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

 
Процедура УбитьСеансыВНочи() Экспорт
    
    Таб = Новый ТаблицаЗначений;    
    Таб.Колонки.Добавить("Пользователь");
    Таб.Колонки.Добавить("ПользовательСсылка");
    Таб.Колонки.Добавить("Номер");
    //Таб.Колонки.Добавить("Поле");
    СеансыИнформационнойБазы = ПолучитьСеансыИнформационнойБазы();
    НомераСеансов = Новый Массив;
    стСписокКРасстрелу = "";
    Для Каждого СеансИБ Из СеансыИнформационнойБазы Цикл
        если не Пользователи.ЭтоПолноправныйПользователь(СеансИБ.Пользователь, Истина) и СеансИБ.ИмяПриложения = "1CV8C" тогда
            ЗадачиЗапрос = Новый Запрос; //Не отключаются пользователи с полными правами, конфигураторы и фоновые задания
            ЗадачиЗапрос.Текст = "выбрать * из регистрсведений.протоколработыпользователей где пользователь=&юзер и дата > &датаубийства";
            Пользователь = Справочники.Пользователи.НайтиПоНаименованию(СеансИБ.Пользователь.ПолноеИмя,Истина);
            
            стРоли = РегистрыСведений.ИсполнителиЗадач.РолиИсполнителя(Пользователь);
            стРольПерманентногоПользователя = Справочники.РолиИсполнителей.НайтиПоНаименованию("ПользователиНеотключаемыеПоНеактивностиСеанса",Истина); //тут прописывается имя роли, входящие в нее пользователи не отключаются
            стПерманентныйПользователь = Ложь;
            Для Каждого ЭлементМассива из стРоли Цикл
                если ЭлементМассива.Владелец.Наименование = стРольПерманентногоПользователя.Наименование тогда
                    стПерманентныйПользователь = Истина;
                    Прервать;
                конецесли;
            КонецЦикла;        
            
            Если Не стПерманентныйПользователь Тогда 
            
                ЗадачиЗапрос.УстановитьПараметр("юзер", Пользователь);
                ЗадачиЗапрос.УстановитьПараметр("датаубийства", ТекущаяДата() - 1800);
                Результат = ЗадачиЗапрос.Выполнить();
                Если Результат.Пустой() Тогда
                    Сеанс = Таб.Добавить();
                    Сеанс.Пользователь             = СеансИБ.Пользователь.Имя;
                    стСписокКРасстрелу            = стСписокКРасстрелу + СеансИБ.Пользователь.Имя + " ";
                    Сеанс.Номер                 = СеансИБ.НомерСеанса;
                    НомераСеансов.Добавить(СеансИБ.НомерСеанса);
                    //Сеанс.ПользовательСсылка      = НайтиСсылкуПоИдентификаторуПользователя(СеансИБ.Пользователь.УникальныйИдентификатор);
                конецесли;
            
            КонецЕсли;
        
        конецесли;
    КонецЦикла;
    
    если НомераСеансов.Количество()>0 тогда
        
        ПараметрыАдминистрирования = АдминистрированиеКластераКлиентСервер.ПараметрыАдминистрированияКластера();
        ПараметрыАдминистрирования.АдресАгентаСервера = "имя_сервера";
        ПараметрыАдминистрирования.ПортАгентаСервера = 7540; //по умолчанию в 1С используется 1540
        ПараметрыАдминистрирования.ПортКластера = 7541; //по умолчанию в 1С используется 1541
        ПараметрыАдминистрирования.ИмяАдминистратораКластера = "имя_администратора_кластера";
        ПараметрыАдминистрирования.ПарольАдминистратораКластера = "пароль_администратора_кластера";
        ПараметрыАдминистрированияИБ = АдминистрированиеКластераКлиентСервер.ПараметрыАдминистрированияИнформационнойБазыКластера();
        ПараметрыАдминистрированияИБ.ИмяВКластере = "имя_базы";
        ПараметрыАдминистрированияИБ.ИмяАдминистратораИнформационнойБазы = "имя_администратора_базы";
        ПараметрыАдминистрированияИБ.ПарольАдминистратораИнформационнойБазы = "пароль_администратора_базы";
        
        СтруктураСеанса = Новый Структура;
        СтруктураСеанса.Вставить("Свойство", "Номер");
        СтруктураСеанса.Вставить("ВидСравнения", ВидСравнения.ВСписке);
        СтруктураСеанса.Вставить("Значение", НомераСеансов);
        Фильтр = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(СтруктураСеанса);
        
        АдминистрированиеКластераКлиентСервер.УдалитьСеансыИнформационнойБазы(ПараметрыАдминистрирования,ПараметрыАдминистрированияИБ, Фильтр);
        
        ЗаписьЖурналаРегистрации("УдалениеПользователейВНочи", УровеньЖурналаРегистрации.Информация, , , "Список пользователей к отключению: " 
        + стСписокКРасстрелу);
        
    конецесли;
    
КонецПроцедуры

 

См. также

Комментарии
2. Сергей Любезнов (sergathome) 15.05.18 15:06 Сейчас в теме
Эх ребяты, где ж вы были года 3 назад, когда нас угораздило вляпаться в релиз платформы, который не освобождал лицензии...
3. Ildar Gabdrakhmanov (spezc) 446 15.05.18 15:16 Сейчас в теме
А штатное время засыпания и время завершения спящего? Чем хуже.
5. Алексей Богачев (aabogachev) 90 15.05.18 16:00 Сейчас в теме
(3) ну хотя бы тем, что виджеты постоянно обновляются и сеанс никогда не станет спящим. кроме виджетов куча всяких штук которые проверяют уведомления и т.п. поэтому приложение будучи свёрнутым все равно остается живым днями, ночами, неделями, месяцами, годами. как угодно. нас это не устраивает. нам хочется чтобы пользователи поработали и закрыли приложение. если надо свернули, но были готовы к тому, что оно прекратит работу само. на этом мы экономим большие деньги.

настройки в базе по освобождению зависших/спящих сеансов сделаны, но таковыми сеансы становятся только тогда, когда приложение завершило свою работу "некорректно"
4. Саша Саша (o4karek) 15.05.18 15:26 Сейчас в теме
А каким образом формируется анализируемый регистр сведений?
ЗЫ: С ДО не знаком
6. Алексей Богачев (aabogachev) 90 15.05.18 16:11 Сейчас в теме
(4) есть общий модуль "ПротоколированиеРаботыПользователей". Там куча функций и процедур, которые пишут в этот РС в зависимости от тех или иных событий и действий пользователя в системе (кстати, чтобы это происходило должна быть включена настройка "Настройка и Администрирование" - "Настройка прав доступа" - "Протоколировать работу пользователей")

Например когда пользователь открывает приложение происходит это

ПротоколированиеРаботыПользователей.ЗаписатьВходВСистему();

и т.п.

вот (скриншот) список событий которые РС протоколирует
Прикрепленные файлы:
7. Саша Саша (o4karek) 15.05.18 16:20 Сейчас в теме
(6) Понял. Т.е. это не совсем честная активность? Это так активность, которую отслеживает подсистема ДО?
Т.е. если я решу доработать ДО и воткну туда что-то, что этим общим модулем не пользуется, предложенное регламентное задание может этот сеанс выстричь даже во время работы. Я правильно понял?
9. Алексей Богачев (aabogachev) 90 15.05.18 16:44 Сейчас в теме
(7) если вы доработаете и будете отслеживать "свои" действия, которые запихнете в этот РС - то конечно оно отработает запрос, найдет их и не выкинет пользователя. выборка то будет не пустой. только вид действия надо будет добавить в Перечисление, скриншот которого я положил выше. все просто.
11. Саша Саша (o4karek) 15.05.18 17:13 Сейчас в теме
(9) Ну тогда (ИМХО) стоит откорректировать заголовок и/или начало статьи. Я подумал, что сделано некоторое универсальное регламентное задание, которое для примера вклеено в ДО.
А у вас сделано специализированный вариант для конкретной конфы. Он не становится от этого плохим, просто стоит сразу об этом сказать :)
8. Сан Саныч (herfis) 254 15.05.18 16:22 Сейчас в теме
Идея проста и понятна. Весь дьявол - в критериях определения активности.
Если пользователь, скажем, в течение получаса заполняет новый документ - это как зафиксируется в протоколе?
10. Алексей Богачев (aabogachev) 90 15.05.18 16:46 Сейчас в теме
(8) никак. как только мы столкнемся с подобного рода проблемами - мы передвинем планку, то есть рег задание будет стартовать не раз в 30 минут, а раз в час и т.п.
но и в приведенном вами примере, на сколько я помню, если открыть файл "на редактирование" а потом закрыть приложение, потом снова открыть, оно "поймет" что файл захвачен на редактирование и попробует поискать в темповой папке ваш файл, который вы "так долго редактировали". так что пример не совсем удачный, но я понял что вы имеете в виду, пока для нас это не проблема.
12. Сан Саныч (herfis) 254 15.05.18 17:25 Сейчас в теме
(10) Мне показалось, что вы позиционировали решение как универсальное.
Если речь об учетной системе предприятия, то подобные сценарии не являются чем-то невероятным.
"Честную" активность, к сожалению, можно будет определять только если соответствующую возможность добавят в платформу.
Как промежуточный вариант, в принципе, можно реализовать такое: выдавать пользователю предупреждение о завершении сеанса с большим таймаутом при длительном отсутствии активности по протоколу а при отмене предупреждения пользователем - записывать это событие в протокол.
ЗЫ. Правда, при такой схеме нет особой необходимости в регламентном задании :) Зависшие сеансы и так станут спящими и перестанут "есть" лицензию. Остаются только сеансы с какими-нить висящими модальными окошками. Но ими, в принципе, можно пренебречь, так как они вряд ли сделают погоду.
13. Алексей Богачев (aabogachev) 90 15.05.18 17:45 Сейчас в теме
(12) вы правы, если делать "универсально", то так и следует поступить, но это можно оставить для тех, кто захочет оптимизировать данное решение, у меня "это" работает уже полгода, как в том анекдоте про сисадмина - "работает и работает, не надо ничего трогать".
20. Виктор Назаров (androgin) 23.05.18 03:39 Сейчас в теме
(13) а чем журнал регистрации не устраивает?
14. kolya_tlt kolya_tlt (kolya_tlt) 11 16.05.18 14:41 Сейчас в теме
как и все разработчики 1С:ДО решение наполнено запросами в цикле, очень жаль ...
зы у вас реально Елен Николаевн так много в компании?
15. Алексей Богачев (aabogachev) 90 16.05.18 15:13 Сейчас в теме
(14) я к сожалению не разработчик, я просто временно решаю проблемы. так сказать создаю костыли. и мне за это платят.
Елен Николавн да, много.
17. Александр Ярошенко (teller) 17.05.18 09:46 Сейчас в теме
(15)
так сказать создаю костыли. и мне за это платят
- тут все такие, никто блокчейны не изобретает
18. kolya_tlt kolya_tlt (kolya_tlt) 11 17.05.18 14:13 Сейчас в теме
(15) вообще сложно человека перед конфигуратором назвать разработчиком, но мы все эти делаем, а в резюме пишим - программист :)
19. Виктор Назаров (androgin) 19.05.18 00:19 Сейчас в теме
Вот это запускается у каждого пользователя само каждые 20 мин (подписка или через обработчик ожидания - сами решите, как вам угодно!):

// на клиенте
Процедура ЗавершитьНеактивныйСеансКлиент() Экспорт
	СеансНеАктивен = ПростойСеансаПоЖурналуРегистрации();
	Если СеансНеАктивен Тогда
	    ЗавершитьРаботуСистемы();        	
	КонецЕсли;
КонецПроцедуры

// на сервере
Функция ПростойСеансаПоЖурналуРегистрации() Экспорт
	
	СеансНеАктивен = Ложь;
	
	// только последние 20 минут
	ДатаНачала = ТекущаяДата()-1200;
	ДатаОкончания = ТекущаяДата();
	
	МассивСобытий = Новый Массив;
	МассивСобытий.Добавить("_$Data$_.New");
	МассивСобытий.Добавить("_$Data$_.Update");
	МассивСобытий.Добавить("_$Data$_.Delete");
	МассивСобытий.Добавить("_$Data$_.Post");
	МассивСобытий.Добавить("_$Data$_.Unpost");
	
	ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(Пользователи.ИдентификаторПользователяИБ());
	Фильтр = Новый Structure("ДатаНачала, ДатаОкончания, Пользователь, Событие", ДатаНачала, ДатаОкончания, ПользовательИБ, МассивСобытий);
	
	ТЗ = Новый ТаблицаЗначений;
	ТЗ.Колонки.Добавить("Дата");
	ТЗ.Колонки.Добавить("Пользователь");
	ТЗ.Колонки.Добавить("ИмяПользователя");
	ТЗ.Колонки.Добавить("Компьютер");
	ТЗ.Колонки.Добавить("Событие");
	ТЗ.Колонки.Добавить("ПредставлениеДанных");
	
	ВыгрузитьЖурналРегистрации(ТЗ, Фильтр,"Дата, ИмяПользователя, Компьютер, Событие, ПредставлениеСобытия , ПредставлениеДанных");
	
	Если ТЗ.Количество() = 0 Тогда
		СеансНеАктивен = Истина;         	
	КонецЕсли;
	
	Возврат СеансНеАктивен;
	
КонецФункции
Показать

Меня устраивает )))
Оставьте свое сообщение