1.7. События активности пользователя в форме

Прикладной код может узнать, что пользователь перестал работать в форме и что он к ней вернулся.

Активность отслеживается отдельно для главной формы приложения и каждой MDI-формы. У модальных форм и лукапов своего отсчёта нет. Работа в них продлевает активность формы, из которой они открыты.

Added in version 1.29.0-ms5.

1.7.1. Включение и время бездействия

Механизм включается метаданными. Форма отслеживается, если у представления её главной выборки задан атрибут View.Representation.userIdleTimeout. Настраивать сервер для этого не нужно.

<representation name="Head" userIdleTimeout="60"/>

Атрибут задаёт время бездействия в секундах. Значение 0 отключает отслеживание формы. Форма без атрибута тоже не отслеживается. Значение читается один раз при открытии формы и дальше не меняется.

Общее время бездействия для многих форм базы задают умолчанием в конфигурации сервера, секцией Configuration.Databases.Database.UserActivity:

<database alias="...">
    <userActivity idleTimeout="300"/>
</database>

Умолчание применяется к формам, у которых атрибут в представлении главной выборки не задан. Значение атрибута перекрывает умолчание. Если секции нет, нет и умолчания, но формы со своим атрибутом отслеживаются всё равно. Конфигурация перечитывается только при перезапуске сервера.

Если ни одна открытая форма не отслеживается, механизм не расходует ресурсы сервера.

Note

Не путайте с Configuration.SessionPool.idleClientTimeout. Тот механизм решает задачу безопасности: он отключает бездействующего клиента от сессии, см. Отключение бездействующих клиентов. Здесь клиент остаётся подключённым, а прикладной код получает уведомление.

1.7.2. Прикладные события

События приходят в главную выборку формы без аргументов:

Что произошло

Событие

Обработчик в Avi-классе

Пользователь перестал работать в форме

form.UserIdle

onUserIdle()

Пользователь вернулся к работе в форме

form.UserActive

onUserActive()

Обработчики объявляются в Avi-классе главной выборки формы методами с аннотацией @Event. Если обработчика нет, форма событие пропускает. Это не ошибка.

1.7.3. Что считается активностью в форме

На этой странице командой называется сообщение, которое клиент отправляет серверу, когда пользователь выполняет действие в форме. Это не то же самое, что команда браузерного плагина.

Активность формы — это любая команда этой формы или открытой из неё модальной формы, лукапа или диалога. Примеры действий, которые отправляют команду:

  • нажатие кнопки, пункта меню или горячей клавиши;

  • переход по записям списка, разворачивание узла дерева, сортировка, применение фильтра;

  • редактирование значения в поле, вставка и удаление записи, сохранение и отмена;

  • работа в модальной форме, открытой из этой формы, и ответ на её диалог.

Активностью не считается:

  • автоматическое обновление данных по таймеру: пользователь в нём не участвует;

  • действия вне форм: работа с панелью уведомлений и закрытие приложения;

  • движение мыши, прокрутка и набор текста в поле ввода: команд они не отправляют.

1.7.4. Неочевидные случаи

Набор текста и прокрутка списка. Пока пользователь набирает значение в поле, команда не отправляется, и долгий набор выглядит как простой. То же с прокруткой уже загруженной части списка. Активность засчитается, когда пользователь закончит ввод значения или прокрутит список за пределы загруженной части.

Открытый диалог. Ожидание ответа на диалог активностью не считается. Забытый на ночь диалог даст UserIdle по истечении времени бездействия. Ответ на диалог — активность: форма получит UserActive, и только потом продолжится прерванная операция. Если ожидание закончилось без ответа, по таймауту или из-за разрыва связи, активности нет: пользователь к форме не вернулся.

Долгая команда. Пока сервер выполняет команду формы, UserIdle не придёт. Время бездействия отсчитывается после завершения команды.

Невыполненная команда. Если сервер не выполнил команду, потому что форма к этому моменту уже изменилась, активность всё равно продлевается: пользователь действие совершил.

Закрытие формы в простое. Закрытие начинается такой же командой, как любая другая. Поэтому форма сначала получит UserActive, а затем beforeCloseForm. Если обработчик UserActive захватывает ресурс, ресурс будет захвачен и тут же отпущен. Сервер не может заранее знать, что команда закроет форму, поэтому обработчик должен быть к этому готов, см. Рекомендации прикладному разработчику.

Разрыв связи с клиентом. Отключение клиента отсчёт не останавливает: форма сессии, от которой отключился клиент, тоже должна освободить занятые ресурсы. Отслеживание прекращается, когда закрывается форма или сессия.

1.7.5. Когда и в каком порядке приходят события

  1. UserIdle отправляется, когда простой формы достиг времени бездействия. Событие может опоздать: сервер проверяет формы периодически. Период проверки равен половине наименьшего времени бездействия среди открытых отслеживаемых форм, но не меньше одной и не больше тридцати секунд. Опоздание не превышает этого периода.

  2. UserActive отправляется до того, как сервер выполнит команду, которая его вызвала. Если пользователь вернулся, ответив на диалог, событие отправляется до продолжения прерванной операции.

  3. События строго чередуются: UserActive приходит только после UserIdle, дублей нет ни в ту, ни в другую сторону. Начальное состояние формы — активна.

  4. События приходят, пока закрытие формы ещё можно отменить: результатом onCloseFormQuery, отказом пользователя сохранять данные или ошибкой обработчика beforeCloseForm. Форма, закрытие которой отменили, работает дальше как обычно. Когда закрытие стало окончательным, события прекращаются. Ресурсы, освобождённые в простое, остаются освобождёнными, окончательную очистку выполняет обработчик beforeCloseForm. Если этот обработчик показал диалог и пользователь долго не отвечает, форма может получить UserIdle во время закрытия.

  5. Исключение обработчика записывается в журнал сервера и дальше не передаётся. Ошибка в обработчике UserActive не отменяет команду. Ошибка в обработчике UserIdle не мешает проверке остальных форм, повторно событие не отправляется.

1.7.6. Рекомендации прикладному разработчику

Один из вариантов использования — на время простоя освобождать занятые формой ресурсы, например прикладные блокировки, и захватывать их заново, когда пользователь вернётся к работе.

Обработчики должны быть готовы к повторному вызову: событие может прийти, когда ресурс уже освобождён или уже захвачен. UserActive должен переживать и случай, когда освобождённый ресурс за время простоя занял другой пользователь. Неудачный захват — нормальный сценарий, его нужно обработать.

Готового признака «форма в простое» механизм не даёт. Если он нужен прикладному коду, его ведут в обработчиках: события чередуются без дублей, поэтому состояние всегда известно.