1с параметры сеанса фонового задания
Длительные операции на сервере
Область применения: управляемое приложение.
1. При разработке конфигураций следует избегать длительных вызовов из клиентского кода в серверный. Все длительные серверные вызовы, которые могут выполняться более 8 секунд в обычных сценариях работы пользователя, следует выполнять асинхронно, с помощью фонового задания.
К таким операциям относятся: формирование отчета, групповая обработка объектов, загрузка или выгрузка данных в другое приложение, заполнение больших табличных частей и т.п.
В противном случае такие вызовы могут привести к потере работоспособности приложения или затруднению работы с ним:
- браузер может предложить прекратить длительно выполняющийся сценарий, после чего приложение станет неработоспособным;
- веб сервер может прервать длительное обращение к серверу 1С:Предприятия и вернуть ошибку 504 (шлюз не отвечает);
- в случае длительного выполнения операции, у пользователя нет возможности отменить ее.
2.1. Общий подход к асинхронному выполнению длительных серверных операций с помощью фонового задания:
-
Код, выполняющий длительную обработку данных, располагается в модуле менеджера объекта* или в общем модуле. Результат своей работы он помещает во временное хранилище;
а для прочих мест – выводится блокирующая форма ( РежимОткрытияОкна = БлокироватьОкноВладельца ), на которой размещена декорация с анимированной картинкой и кнопка «Отмена» :
2.2. Асинхронное формирование отчета требуется только для тех отчетов, которые
- разработаны без использования СКД или с использованием СКД, но с переопределенной процедурой формирования отчета (переопределен обработчик кнопки «Сформировать» или в обработчике модуля отчета ПриКомпоновкеРезультата устанавливается СтандартнаяОбработка = Ложь ).
- и формирование которых, как правило, занимает длительное время.
Поведение таких отчетов должно быть максимально похожим на поведение отчетов на базе СКД, а именно:
- форму отчета не следует блокировать на время его формирования;
- пользователь может изменить настройки и переформировать отчет, не дожидаясь окончания его формирования;
- при закрытии формы отчета, формирование отчета прерывается.
3. При использовании в конфигурации Библиотеки стандартных подсистем в распоряжении разработчика имеются вспомогательные функции и процедуры общих модулей ДлительныеОперации , ДлительныеОперацииКлиент , а также процедура УстановитьСостояниеПоляТабличногоДокумента общего модуля ОбщегоНазначенияКлиентСервер .
Пример выполнения функции в фоновом задании при использовании в конфигурации Библиотеки стандартных подсистем. В модуле менеджера объекта размещена функция, которая выполняет поиск настроек и возвращает их:
Функция ОпределитьНастройкиУчетнойЗаписи(АдресЭлектроннойПочты, Пароль) Экспорт
.
Возврат Настройки;
КонецФункции
В форме объекта выполняется вызов этой функции в фоновом задании в три этапа:
1) запуск фонового задания на сервере,
2) подключение обработчика завершения фонового задания на клиенте,
3) обработка результата выполнения фонового задания.
&НаКлиенте
Процедура НастроитьПараметрыПодключенияАвтоматически()
// 1. Запуск фонового задания на сервере.
ДлительнаяОперация = НачатьПоискНастроекУчетнойЗаписи();
// 2. Подключение обработчика завершения фонового задания.
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
Оповещение = Новый ОписаниеОповещения("ПриЗавершенииПоискаНастроек", ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, Оповещение, ПараметрыОжидания);
КонецПроцедуры
&НаСервере
Функция НачатьПоискНастроекУчетнойЗаписи()
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
Возврат ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, "Справочники.УчетныеЗаписиЭлектроннойПочты.ОпределитьНастройкиУчетнойЗаписи",
АдресЭлектроннойПочты, Пароль);
КонецФункции
// 3. Обработка результата выполнения фонового задания.
&НаКлиенте
Процедура ПриЗавершенииПоискаНастроек(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда // Пользователь отменил задание.
Возврат;
КонецЕсли;
Если Результат.Статус = "Ошибка" Тогда
ВызватьИсключение Результат.КраткоеПредставлениеОшибки;
КонецЕсли;
Настройки = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
УдалитьИзВременногоХранилища(Результат.АдресРезультата);
УстановитьНастройкиУчетнойЗаписи(Настройки);
Методическая рекомендация (полезный совет)
3.1. При каждом выполнении фонового задания его результат помещается во временное хранилище на время жизни формы:
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, ПараметрФоновогоЗадания);
Если длительная операция выполняется пользователем многократно, пока эта форма открыта, то временные хранилища накапливаются, что вызывает рост потребления памяти. Поэтому для уменьшения расхода оперативной памяти в большинстве случаев рекомендуется очищать временное хранилище сразу после получения результата фонового задания:
Настройки = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
УдалитьИзВременногоХранилища(Результат.АдресРезультата); // Данные во временном хранилище больше не требуются.
Если же результат фонового задания требуется сохранять на протяжении нескольких серверных вызовов, то необходимо передавать фиксированный адрес заранее инициализированного временного хранилища:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ)
АдресРезультатаФоновогоЗадания = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор); // Резервируем адрес временного хранилища
КонецПроцедуры
&НаСервере
Функция НачатьПоискНастроекУчетнойЗаписи()
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
ПараметрыВыполнения.АдресРезультата = АдресРезультатаФоновогоЗадания; // всегда используем одно и то же временное хранилище
Возврат ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения,
"Справочники.УчетныеЗаписиЭлектроннойПочты.ОпределитьНастройкиУчетнойЗаписи",
АдресЭлектроннойПочты, Пароль);
КонецФункции
4. Если в конфигурации реализуются алгоритмы, инициирующие запуск фоновых заданий или запись данных информационной базы без участия пользователя (например, регулярное обновление информации в открытой форме), то в них следует проверять, что в текущем сеансе не установлен монопольный режим. В противном случае, следует блокировать попытки выполнения таких действий. Например:
Если МонопольныйРежим() Тогда
Возврат;
КонецЕсли;
5. В некоторых случаях возникает необходимость в выполнении длительных операций, требующих установки монопольного режима доступа к информационной базе. Например:
Обновление данных ИБ при первом интерактивном запуске программы после обновления конфигурации; Выгрузка данных информационной базы в файл для перехода в сервис; Использования монопольного режима для снижения времени выполнения массовых операций по изменению данных;При этом необходимо сначала устанавливать монопольный режим, а затем выполнять запуск фонового задания, которое реализует саму длительную операцию. В этом случае фоновым заданием будет унаследован монопольный режим, ранее установленный из пользовательского сеанса (см. документацию к платформе).
На время выполнения этого фонового задания следует блокировать весь интерфейс приложения, открывая форму ожидания завершения операции в режиме РежимОткрытияОкна = БлокироватьВесьИнтерфейс. Блокировать интерфейс приложения требуется потому, что на время выполнения задания полноценная работа пользователя с приложением уже невозможна:
- Если пользователь(*) попытается записать какой-либо объект, это приведет к ошибке (из-за установленного монопольного режима);
- В ряде случаев могут запускаться фоновые задания в качестве реакции на действия пользователя случае (при поиске в динамическом списке, при вводе по строке, формировании отчетов и пр.), которые также завершатся с ошибкой.
Кроме того, на самой форме ожидания длительной операции не следует размещать элементы управления, которые могут приводить к запуску таких фоновых заданий. Например: поля ввода, динамические списки и отчеты.
* Примечание: ошибки записи также возникают в тех случаях, когда объекты записываются программно, например, из обработчиков ожидания. В них также следует проверять монопольный режим согласно п.5.
1С:Предприятие > 8.1.8, клиент-серверная архитектура, MS SQL.
Общий неглобальный серверный модуль. Обработка с одной формой, одной кнопкой и одним табличным полем.
Нажав кнопку на форме, запустить некий долгий алгоритм расчета так, чтобы при этом форма была доступна для нажатия других кнопок, менюшек, перемещения.
По окончании расчета передать результат расчета в табличное поле и отобразить результат.
Методика:
Как показала практика, из отработавшего фонового задания вернуть штатным путем каке-либо данные невозможно. Имеется 2 способа, позволяющих это
делать:
1) фоновое задание пишет результат своей работы в БД, обработка отслеживает, что фоновое задание завершилось и считывает из БД результат. В качестве места хранения результата предлагается
использовать регистр сведений, где измерение хранит UID экземпляра фонового задания, а ресурс имеет тип ХранилищеЗначений.
2) извращенный способ – передать значение через программную генерацию исключения (оператор «ВызватьИсключение»).
Решение:
Описывать способ с регистром сведений не буду, так как это достаточно просто реализовать, а минусом является необходимость добавления в конфигурацию регистра сведений. Поэтому опишу вариант с
«ВызватьИсключение»:
Процедура общего модуля:
Модуль формы обработки:
Результат:
Жмем кнопку. 15 секунд наслаждаемся перетаскиванием формы и прочими действиями (кроме закрытия).
Потом резко (само! шайтан! :) заполнится табличное поле на форме, чего и следовало ожидать.
Нагрузочные испытания проведены на передаче таблицы значений из 2 полей с количеством строк 100 тыс.
шт. – успешно.
Надеюсь, статья будет вам полезна.
Выражаю благодарность всем, кто помог мне осуществить данную операцию.
С уважением, Алексей Шачнев.
Вместо обработки ожидания использовал отправку датаграммы из фонового задания форме посредством MS WinSock (ActiveX)
Нужно было выполнить заполнение дерева в фоне (что бы не блокировать основной интерфейс). Нашел эту статейку.
Собственно удалось выполнить фоновое задание без "ВызватьИсключение".
8.2.19.68 (Управляемое приложение)
Использование параметров сеанса
Область применения: управляемое приложение, мобильное приложение, обычное приложение.
1.1. Параметры сеанса предназначены для хранения значений определенных типов для каждого клиентского сеанса на время работы этого сеанса. Инициализацию параметров сеанса следует выполнять в модуле сеанса (см. ниже раздел 2.1), а их значения рекомендуется использовать в запросах и условиях ограничения доступа к данным для текущего сеанса.
Примеры параметров сеанса:
- ТекущийПроект – тип СправочникСсылка.Проекты ;
- ОбменДаннымиВключен – тип Булево ;
- РабочееМестоКлиента – тип СправочникСсылка.РабочиеМеста .
Параметры сеанса доступны из встроенного языка 1С:Предприятия , например:
В этом случае, для установки или получения значения параметра сеанса текущий пользователь должен быть наделен соответствующим правом.
Также они могут использоваться в текстах ограничений доступа, например:
ГДЕ Документ.Автор = &ТекущийПользователь
В последнем случае для получения значения параметра сеанса наличия у текущего пользователя соответствующего права не требуется.
1.2. Не рекомендуется использовать параметры сеанса для хранения значений, используемых исключительно в клиентской логике. Поскольку в клиент-серверном варианте 1С:Предприятия параметры сеанса хранятся на сервере, то любое их считывание или изменение в процессе работы на клиенте потребует дополнительного серверного вызова и увеличит объем передаваемых данных с клиента на сервер и обратно.
В таких случаях следует использовать глобальные переменные модуля управляемого приложения (и обычного приложения – для режима обычного приложения, соответственно).
1.3. Также не рекомендуется использовать параметры сеанса для кеширования вычисленных значений, которые многократно используются в серверной бизнес-логике. В таких случаях следует определять функцию в серверном общем модуле с повторным использованием возвращаемых значений. Исключение составляют случаи, когда время вычисления результата функции модуля с повторным использованием возвращаемых значений соизмеримо с периодом сброса платформенного кеша.
Установка параметров сеанса "по требованию"
2.1. Не следует производить инициализацию параметров сеанса при запуске программы, так как:
- не все параметры сеанса запрашиваются из кода конфигурации при запуске программы.
- при работе программы возможно намеренное обнуление значений параметров сеанса из кода на встроенном языке.
Правильным способом установки значений параметров сеанса является установка значений "по требованию" в обработчике УстановкаПараметровСеанса модуля сеанса. Т.е. параметры сеанса должны быть инициализированы только в тот момент, когда к ним происходит первое обращение, как к неустановленным.
Пример установки параметров сеанса "по требованию":
Если ИменаПараметровСеанса = Неопределено Тогда
// Раздел установки параметров сеанса при начале сеанса (ИменаПараметровСеанса = Неопределено)
// Выполняется установка параметров сеанса, которые можно инициализировать
// при начале работы системы
Иначе
// Установка параметров сеанса "по требованию"
// Параметры сеанса, инициализация которых требует обращения к одним и тем же данным
// следует инициализировать сразу группой. Для того, чтобы избежать их повторной инициализации,
// имена уже установленных параметров сеанса сохраняются в массиве УстановленныеПараметры
УстановленныеПараметры = Новый Массив;
Для Каждого ИмяПараметра Из ИменаПараметровСеанса Цикл
УстановитьЗначениеПараметраСеанса(ИмяПараметра, УстановленныеПараметры);
КонецЦикла;
// Установить значения параметров сеанса и возвратить имена установленных параметров сеанса
// в параметре УстановленныеПараметры.
//
// Параметры
// ИмяПараметра - Строка - имя параметра сеанса, который требуется установить (проинициализировать).
// УстановленныеПараметры - Массив - массив, в который добавляются имена
// установленных (проинициализированных) параметров.
//
Процедура УстановитьЗначениеПараметраСеанса(Знач ИмяПараметра, УстановленныеПараметры)
// Если в данном вызове УстановкаПараметровСеанса параметр ИмяПараметра уже
// был установлен - возврат.
Если УстановленныеПараметры.Найти(ИмяПараметра) <> Неопределено Тогда
Возврат;
КонецЕсли;
Если ИмяПараметра = "ТекущийПользователь" Тогда
ПараметрыСеанса.ТекущийПользователь = <значение>;
ПараметрыСеанса.<другой параметра сеанса> = <значение>;
УстановленныеПараметры.Добавить(ИмяПараметра);
УстановленныеПараметры.Добавить("<другой параметра сеанса>");
КонецЕсли;
(8) Можете концепцию объяснить, я пока вообще ничего не понимаю. Если бы этот механизм делал я, то нет ничего проще - параметр сеанса это глобальная переменная, которая видна из любого места, при этом в каждом сеансе каждого пользователя он свой, то есть если в одном сеансе я этот параметр поменял, то в другом сеансе другого пользователя этот параметр сеанса не изменился. С тех пор, как подобный параметр сеанса описан в конфигураторе и ему присвоен тип, он уже прям сразу доступен для чтения, например если я описал ему тип Справочник.ФизическиеЛица, то я читаю ПараметрыСеанса.МоёФизлицо и там лежит пустая ссылка. При такой концепции ни инициализация, ни модуль сеанса не нужны от слова совсем.
Теперь то, как оно на самом деле происходит. После запуска программы, несмотря на то, что МоёФизлицо описано в конфигураторе, чтение ПараметрыСеанса.МоёФизлицо дает ошибку. В хелпе написано что его за каким-то лядом надо инициализировать, причём ПриНачалеРаботыСистемы его инициализировать не получается, а только в модуле сеанса, который тоже непонятно зачем выдумали. Ну ОК, в модуле сеанса типа есть Процедура УстановкаПараметровСеанса(ТребуемыеПараметры), причём в хелпе написано что эта процедура вызывается один раз с ТребуемыеПараметры = Неопределено в момент старта системы, а в следующие разы оно срабатывает когда надо какой-то параметр сеанса переинициализировать (нафейхоа?) и типа их массив как раз в ТребуемыеПараметры и лежит. При этом, если поставить брейкпойнт при УстановкаПараметровСеанса, то в ПараметрыСеанса коллекция пустая, несмотря на то, что в конфигураторе их описано сто штук. И как вишенка на торте я вижу, что УстановкаПараметровСеанса вызывается много раз с ТребуемыеПараметры = Неопределено, в том числе не только при начале работы системы, а как раз перед тем, как в совершенно другом модуле совершенно другой обработки я этот параметр читаю. Получается, что если мой параметр сеанса не инициализировать, то его и прочитать не получится, а если прописать в коде инициализацию, то оно будет переинициализироваться каждый раз перед чтением. Видимо я не совсем понимаю концепцию разработчиков этого механизма, а в справке об этом не написано.
Если в ТребуемыеПараметры равно Неопределено, а параметр сеанса вам будет нужен, то инициализируйте его, несмотря на Неопределено.
(0)
>УтановкаПараметровСеанса с параметром Неопределено вызывается каким-то фоновым заданием
Как бы, у фоновых заданий свои сеансы -> в любом фоновом задании будет вызова УтановкаПараметровСеанса с Неопределено.
(10) параметр сеанса надо переинициализировать, если он изменился по бизнес-логике. Например, в параметрах сеанса хранится параметр доступа "Доступные объекты" и админ изменил права доступа. Пользователю можно перезайти в систему, а можно просто нажать кнопку "Обновить". По кнопке "Обновить" Ваш программный код заново инициализирует параметры сеанса, а потом вызовет обновление динамического списка, чтобы сработали новые RLS.
(0) Невнимательно читал. Неинициализированные параметры использовать нельзя - это защита от дурака. Но при первом обращении к неинициализированному параметру сеанса платформа дернет для программиста УстановкаПараметровСеанса с указанием, какой параметр необходимо проинициализировать. И вот если и тогда он не будет проинициализирован - тогда будет исключение.
(4) Ну, ходи из УФ за своим параметром сеанса на сервер. Сделай для этого функцию клиент-серверного общего модуля, чтобы если обращение с клиента - то ходило на сервер за ней.
В старых типовых на ОФ когда-то была подобная говносистема глобальных переменных, охватывающая и клиента и сервер. Но потом от нее отказались, слава богу. Потому что злоупотребление глобальным контекстом - это всегда костыли, чреватые боком. Да и в УФ это особо неэффективно. Да и особенно чревато в силу повсеместной асинхронности.
Если нужно банальное кэширование, то это эффективно делать "по месту". А на уровне общих модулей вообще есть готовый механизм повторного использования возвращаемых значений.
(2) Да. С параметром Неопределено вызывается один раз. Когда-то оно вообще один раз и дергалось. Но в новых версиях 1С для ускорения старта программы реализовали отложенную инициализацию. Чтобы при старте приложения можно было инициализировать необходимый минимум параметров, а остальное - при первом обращении.
(16) Могу скриншоты показать. По-видимому, (12) прав, у фонового задания свои параметры сеанса
Задача: пользователь в какой-то момент времени ввел пароль и система его запомнила до момента закрытия платформы, и пароль можно считать из любого места (модуль формы, модуль объекта, функция общего модуля, которая вызывается из СКД отчёта, а отчёт СКД, судя по всему, выполняется фоновым заданием, у которого свои параметры сеанса). Записывать в базу пароль, естественно, нельзя.
ЗЫ. Общая практика - не хранить пароль вообще никак и никогда. Провел аутентификацию, выдал права (провел авторизацию) - дальше просто используешь эти права.
(18) Там шифровать/расшифровывать надо "на лету", соответственно солёный пароль необходим.
(19) Тогда и говорить лучше не про пароль, а про ключ шифрования. Прямая задача пароля - аутентификация. Лучше сразу не смешивать понятия - может аукнуться.
Ну а так-то - да. Пишешь ключ шифрования в параметр сеанса и потом используешь. На старте по Неопределено инициализируешь каким-то дефолтным значением, которое в бизнес-логике интерпретируешь как пустое.
Не очень понятно, на чем ты споткнулся. То, что у тебя отчет формируется в фоне с пустым ключом шифрования - это не больше чем твое предположение, насколько я понял. Ну так проверь его. По-идее, все там должно быть в порядке.
(17)
>ИМХО, фоновые задания созданные из сеанса пользователя, используют его параметры сеанса.
От "родительского" сеанса берутся только параметры сеанса со значения разделителей.
>Иначе никакой отчет СКД при выполнении в фоне не смог бы использовать RLS
Руками (а не тем, на чём сидят) сделанный RLS использует только параметры сеанса инициализируемые "по запросу" (через УстановкаПараметровСеанса) - они просто инициализируются в сеансе фонового задания так же как и в родительском (если при этом в БД что-то поменялось - значения могут и разойтись).
(0) 1. Инициализировать параметры сеанса ты можешь в любом месте программы в серверном коде
2. Читать неинициализированные параметры сеанса нельзя - вывалится исключение
3. При попытке чтения неинициализированного параметра сеанса вызывается УстановкаПараметровСеанса(<ИмяПараметра>) в модуле сеанса, с именем требуемого параметра. Здесь тебе дают последний шанс инициализировать параметр. Если ты и здесь этого не сделаешь - вывалится исключение (см. пункт 2)
4. При старте программы один раз вызывается УстановкаПараметровСеанса(Неопределено) в модуле сеанса. Здесь ты можешь провести первоначальную инициализацию параметров сеанса, например заполнить неизменяемые (например, ТекущийПользователь). А можешь ничего не делать - решать тебе
5. Параметры сеанса в клиентском приложении и в запущенном из него фоновом задании общие. В этом вся суть параметров сеанса - из-под одного сеанса может быть несколько подключение к базе
Так что смело используй параметры сеанса в качестве глобальной переменной.
Только не забудь её первоначально инициализировать (присвоить ей значение, пусть даже пустое)
Читайте также: