Shutdown clients from Application Server

Hi everybodies,
as our application is rapidly growing, there is a lot of clients attached to Servoy application server.
As the experience tell us, users usually don’t logoff but try to reconnect from another browser instance or tab (please note that we are running version 7.4.3 so we still have problems on opening a new tab from the same browser instance if already connected to the server, see https://forum.servoy.com/viewtopic.php?f=5&t=20896); this is resulting in many duplicated client.

Is it possible configuring the application server to automatically shutdown client after a user defined idle period?
Or also to shutdown a previous connected client if it tries to reconnect from the same ip address?
Is there some documentation about client management for application server?

Many thanks in advance.

Hi,

maybe you can use the UserManager plugin in some batch process, UserManager plugin for Servoy

Regards,
Peter

Is it possible configuring the application server to automatically shutdown client after a user defined idle period?

Yes, that is possible in Servoy, check docu / wiki.

Regards,

First of all, thank you for your replies!

Peter de Groot:
Hi,

maybe you can use the UserManager plugin in some batch process, UserManager plugin for Servoy

Regards,
Peter

Peter, I had a look and it seems interesting to me… did you ever test it? Do you think base version has enough features?

lwjwillemsen:

Is it possible configuring the application server to automatically shutdown client after a user defined idle period?

Yes, that is possible in Servoy, check docu / wiki.

Regards,

lwjwillemsen, I really can’t find anything about it… if you know where to navigate could you give me the link please? I’ll appreciate it so much!!!

Timeout Configuration: http://www.servoyguy.com/knowledge_base … web_client

Some techniques I’ve used in the past…

  1. Simple exit on timeout (Option #1)
  • Add a global date/time in your solution. Hook it into some basic functions, like when the user switches screens, and set it to current time.
    onSolutionOpen, set that global to current time. Also make a call to the scheduler plugin to run every 10 minutes or so, which checks that global. If the difference between the global date/time and current time is > than your timeout time you want (say 15 minutes), then do application.exit(), or whatever you want to exit the app.
  1. Simple exit on timeout (Option #2)
    Use the UserManager plugin. It has a call you can run onSolutionOpen which should essentially do the same as option #1, but using Servoy’s built in idle time. I believe its:
plugins.UserManager.Client().maxIdleTime = X
  1. Sessions based on licensing.
    In your tenant table (or whatever groups users of the same company), add a column for number of licenses. Then check the number of concurrent users under that tenant and enforce the number of concurrent sessions allowed for that company. This would happen onSolutionOpen.
application.addClientInfo('License " + tenantId);
var currentLicenseForTenant = application.getClientCountForInfo('License " + tenantId)
if(currentLicenseForTenant > amountLicensedForThisTenant){
   //show then a dialog that they have too many sessions open, then exit
}
  1. Only allow 1 session per username.
    You can keep track of the session for each user. When the username logs in, kill off their other session. So a user can only be logged in once, and old sessions die upon new session logging in.
    In your user table, add a client_id. Upon logging in add some code that checks if that client_id still has a session, and if so, kill it. Then set the client_id to our new session. Something like:
var oldClient = plugins.UserManager.getClientByUID(userRecord.client_id)
if(oldClient && oldClient.alive){
   oldClient.shutdown()
}
userRecord.client_id = plugins.UserManager.Client().clientId
databaseManager.saveData(userRecord)

Sometimes its appropriate to use multiple of these. For example, using #2, #3, and #4 together can be effective. It would only allow 1 session per username, kill off idle sessions, and limit the number of sessions per tenant/company to comply with your licensing model.

Lastly, make sure you’ve configured our timeout url and redirect stuff for the WebClient: https://wiki.servoy.com/display/public/ … t+Settings
Otherwise they exit and can end up on the login page, which still uses a session. So you can configure what happens when the session times out.

Thanks a lot, Scott!
I will try using the UserManager plugin.
I don’t think that the timeout param in the configuration could be the right solution for me.
It has been always a bit weird to me… even if the param is currently set to the default value of 30 minutes I still have connected clients idle since hours
(and with no transactions alive…)

Hi,

I’ve already used the UserManager plugin in the past to do something similar (but using headless client instead smart/web-client).
Pay attention to the client UID if you try the point 4: be sure that you are closing the right client and to get the right UID.

Hi,

studiomiazzo:
Is it possible configuring the application server to automatically shutdown client after a user defined idle period?

I have written a method using UserManager plugin that will check the idle timing of all connected users and if that exceed a given period of time shut them off the system. You can add a cron job every hour to check if users are idling for more than specified time limit.

// Adding the method to check and remove idle users every hour
		plugins.scheduler.removeJob('remove_idle_users');
		plugins.scheduler.addCronJob('remove_idle_users', '0 0 * * * ?' , scopes.serverUtils.removeIdleUsers , dateNow);

Remove Idle users :

function removeIdleUsers(){
	
	// Define the idle time limit
	var idleTImeLimit = 90;
	
	var now = new Date().getTime();    // Store the seconds when this method is triggered
	var clients = plugins.UserManager.getWebClients();     // Get all the web clients	

	// If any client present, then for each client check the idle time
	if(clients){
		
		clients.forEach(function (element, index, array) {
		
			var idleTime = clients[index].idle.getTime();      // Get the idle time
			
			// If the time difference is more than 90 min, shutdown the client
			if(((now - idleTime)/1000)/60 > idleTImeLimit){
				
				// Skipping the shutdown process for wall monitor
				if(clients[index].userName != 'skippedUser'){
					
					application.output("Client Removed from list :" + clients[index].userName +" at " + new Date() + 
						"idling since : " + clients[index].idle , LOGGINGLEVEL.INFO);
					
					clients[index].shutdown();
				} else {
					
					application.output('Skipped for skipped user :' + clients[index].userName, LOGGINGLEVEL.INFO);
				}
			}
		});
	}
}

Additionally, you could also check if the user logs out as you intend it, and if not put up an annoying message on his next login

  • an educational measure, so to say.

That can be easily done by a flag in the user’s record that gets cleared only on correct logout.
Online banking software is doing this a lot.

sovanm:
I have written a method using UserManager plugin that will check the idle timing of all connected users and if that exceed a given period of time shut them off the system.

Not sure why that was needed. It’s essentially what the plugin does for you automatically. You can set idle times for different deployment types (smart / web) or per user (see Scott’s Option #2).

We are using ‘plugins.UserManager.getClientByUID(clientId).shutdown()’ to force clients to close down.
A list of active clients are shown and each may be selected for termination.
The client is shown as inactive, finally falling off of the active client list after 3 minutes. The client never goes away.
After the timeout and any UI interaction, the client pops up a dialog “Reconnect Failed: Old transaction or locks found, need to restart the solution.”, followed by a solution selection for re-opening a client session, instead of closing the current solution.

This worked in the past, but a Java update snuck in, and seems to have hosed it.

We are running Servoy 7.1, with Java 8, Update 91.
The problem is seen directly executing it from the server or from another computer, so it is not the firewall or network settings, although those have been checked as well.

There was a problem that 7.1 worked around using Java 7: (logged error message below)

Java 7u21 broke server ability to shutdown smart clients
viewtopic.php?f=6&t=20091&p=108148&hilit=error+flushing+message+buffer+to+client#p108148

They are shut down by the server, but do not close and no other client communications seems to work either through this plugin.
So the client doesn’t receive the shutdown message. The registration is complete and the server returns the requested information on the clients.

Is this the same problem as Java 1.7 and Pre-Servoy 7.x, or is this a different issue?

Thanks!
Joe

The Servoy Server error message is
com.servoy.j2db.dataprocessing.Zb Error flushing message buffer to client

This is the trace stack shown in the log:

java.lang.NullPointerException
at sun.awt.SunToolkit.getSystemEventQueueImplPP(Unknown Source)
at sun.awt.SunToolkit.getSystemEventQueueImplPP(Unknown Source)
at sun.awt.SunToolkit.getSystemEventQueueImpl(Unknown Source)
at java.awt.Toolkit.getEventQueue(Unknown Source)
at java.awt.EventQueue.invokeLater(Unknown Source)
at javax.swing.SwingUtilities.invokeLater(Unknown Source)
at com.servoy.j2db.smart.J2DBClient.invokeLater(J2DBClient.java:4063)
at com.servoy.j2db.ClientState.invokeLater(ClientState.java:1705)
at com.servoy.j2db.ClientStub.shutDown(ClientStub.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at sun.rmi.server.UnicastServerRef.dispatch(Unknown Source)
at sun.rmi.transport.Transport$1.run(Unknown Source)
at sun.rmi.transport.Transport$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(Unknown Source)
at sun.rmi.transport.StreamRemoteCall.executeCall(Unknown Source)
at sun.rmi.server.UnicastRef.invoke(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(Unknown Source)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(Unknown Source)
at com.sun.proxy.$Proxy18.shutDown(Unknown Source)
at com.servoy.j2db.dataprocessing.ClientProxy.Zc(ClientProxy.java:168)
at com.servoy.j2db.dataprocessing.Zo.run(Zo.java:20)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

A possible work-around would be to close it yourself, instead of waiting for Servoy to terminate it.
I believe there is a function call in the UserManager plugin to make the client run a method, called “executeMethod”. You could create a global method named “shutdownClient” which does: application.exit()

So instead of calling plugins.UserManager.getClientByUID(clientId).shutdown(), you could call plugins.UserManager.getClientByUID(clientId).executeMethod(globals.shutdownClient, null). It would close the client client-side, then the session would be removed from the server.

The UserManager messages aren’t getting to the client apparently.
I’ve attempted executeMethod, sendMessage as well, without success.

downloaded the Java 6 package (jre-6u45-windows-x64) which permitted me to properly shutdown the selected client,
but got the error (below) in the Java console log on solution start. So it looks like it is definitely the issue with 7.1 and Java 6.

java.lang.UnsupportedClassVersionError: com/sun/javafx/runtime/VersionInfo : Unsupported major.minor version 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(Unknown Source)
at java.lang.ClassLoader.defineClass(Unknown Source)
at java.security.SecureClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.defineClass(Unknown Source)
at java.net.URLClassLoader.access$000(Unknown Source)
at java.net.URLClassLoader$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at com.sun.deploy.config.JfxRuntime.runtimeForPath(Unknown Source)
at com.sun.deploy.config.JREInfo.(Unknown Source)
at com.sun.deploy.config.JREInfo.setInstalledJREList(Unknown Source)
at com.sun.deploy.config.ClientConfig.storeInstalledJREs(Unknown Source)
at com.sun.javaws.Main.launchApp(Unknown Source)
at com.sun.javaws.Main.continueInSecureThread(Unknown Source)
at com.sun.javaws.Main.access$000(Unknown Source)
at com.sun.javaws.Main$1.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)