Dear Community,
I wanted to share an example for which you can monitor if the user has been idle in AIMMS for a certain period.
Why?
You may want to check if your users are not leaving applications open while not using it for long periods , effectively occupying user licenses and compute power while blocking other users.
There already is a timeout for WebUI applications, but this only happens if the browser tab is closed, is made idle by the browser, or the connection is lost - hence, if the user opens the app but simply forgets it open, it will not be automatically ended.
How?
To do this, I have two simple procedures:
Procedure pr_checkIdle {
Body: {
if DataChangeMonitorHasChanged("idle_monitor") then
sp_log += CurrentToString("%c%y-%m-%d %H:%M:%S") + " DataChangeMonitorHasChanged detected change\n";
DataChangeMonitorReset("idle_monitor",s_identifierToMonitor);
empty p_howLongIdle;
else
sp_log += CurrentToString("%c%y-%m-%d %H:%M:%S") + " DataChangeMonitorHasChanged no change\n";
p_howLongIdle += 10;
if p_howLongIdle >= 2[minute] then
ExitAimms;
endif;
endif;
pr_scheduler;
}
}
and
Procedure pr_scheduler {
Body: {
sp_log += CurrentToString("%c%y-%m-%d %H:%M:%S") + " Scheduling for " + MomentToString("%c%y-%m-%d %H:%M:%S%TZ('UTC')", , CurrentToString("%c%y-%m-%d %H:%M:%S%TZ('UTC')"), 10) +"\n";
ep_procedure := 'pr_checkIdle';
sp_log
+= if
ScheduleAt(MomentToString("%c%y-%m-%d %H:%M:%S", , CurrentToString("%c%y-%m-%d %H:%M:%S%TZ('UTC')"), 10),ep_procedure)
then
CurrentToString("%c%y-%m-%d %H:%M:%S") + " Scheduling for " + "Success\n"
else
CurrentToString("%c%y-%m-%d %H:%M:%S") + " Scheduling for " + "Fail"
endif;
}
ElementParameter ep_procedure {
Range: AllProcedures;
}
}
and the following support identifiers:
Set s_identifierToMonitor {
SubsetOf: AllIdentifiers;
Definition: AllIdentifiers - IdleMonitor - AimmsProLibrary - AimmsWebUI + 'webui::CurrentPageId';
}
StringParameter sp_log;
Parameter p_howLongIdle {
Unit: s;
}
The first procedure uses the DataChangeMonitor to verify if any of the identifiers in the specified set have changed since the data monitor was created or changed. If it hasn't changed it updates the idle time and if over 2 minutes, it quits AIMMS. If detects a change, it resets the timer. There is some logging so you can see what happens.
The second procedure re-schedules this same procedure to run again in 10 s in the future.
I also added the following to the PostMainInitialization
DataChangeMonitorCreate("idle_monitor",s_identifierToMonitor,0);
sp_log := CurrentToString("%c%y-%m-%d %H:%M:%S") + " DataChangeMonitorCreate Created\n";
pr_scheduler;
Some considerations:
- You don't need to check this every 10
- this is simply to illustrate the use - You also don't need to kill AIMMS after 2[minutes] - the amount of time is up to you
-
@Chris Kuip suggested to add some warning message in the status bar to allow the user to know that the monitor has detected idle session and will close in X minutes. I would not use a pop-up in this case because it will block actions until close. - You may want to check if your are running in developer mode during the PostMainInitizliation and not start the scheduler in this case
- You may also want to prevent AIMMS quiting if you are running an optimization and are hence “idle” because of this
- My s_identifierToMonitor set currently uses all identifiers expect the ones in the monitoring, in PRO Library and in WebUI, and I force the inclusion of 'webui::CurrentPageId'.
- PRO and WebUI are supporting libraries which I don't think are relevant to be monitored
- If you use the "WebUI State Support” experimental feature (https://documentation.aimms.com/webui/experimental-features.html#current-list-of-experimental-features) you can use the 'webui::CurrentPageId' to check if the user is switching pages, which means they are not idle.
- You may want to make an auto backup of the case before quitting AIMMS so the user can recover when opening again
- If on our Cloud, using the ExitAIMMS will show the “Busy” state but the session is terminated.
Example project attached - hope you enjoy!