Our Java 8 and Spring-based application is generating bulk reports (PDF files) in the background. This might take more than one to two hours. The progress as a percentage value has been updated in the UI (front end) after generating each report, so the UI is active till completing the reports generation, but for some reason we're getting Session Expired messages in the UI from Vaadin framework in the middle of the report generation process.
Vaadin framework version : 7.6.2
Web Server : Tomcat 7
Value for heartbeat duration : default value (no explicit value configured)
Value for session timeout duration in web.xml : 30 min by default
No change for the value for closeIdleSessions (By default closeIdleSessions=false)
Can anyone please help to find the reason?
If the only activity is through pushing out status updates through the #Push websocket, then that might not be enough to postpone session expiration on the servlet level.
You could work around this by ensuring there is a normal request from the client every now and then just to reset the session timeout. This can be done by enabling UI polling with a long interval, e.g. ui.setPollInterval((int) Duration.ofMinutes(25).toMillis());.
Remember to disable the polling after the long task is done, or it will continue to keep your session alive.
Related
I am developing a Java web application using Spring.
What I would like to do is that after the user gets to a page, the code starts running a function every 10 seconds, keeping track on the time the last action was performed.
I tried to do so with a Scheduler but it starts running immediately - and not only after the user gets to a page.
#Scheduled(fixedRate = 60000)
public void run(String param) {
//just an example of action to be performed repeatedly
System.out.println("Previously performed action was " + new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(previousActionTime)) + " with " + param);
//update previousActionTime
previousActionTime.setSeconds(previousActionTime.getSeconds() + 10);
}
Moreover I don't know what it is a convenient way to store the time when the last action automated action was performed.
The scheduler should be somehow activated when browsing to the page:
#RequestMapping(value = "/hellopage", method = { RequestMethod.POST, RequestMethod.GET })
public String hellopage(HttpServletRequest request, HttpServletResponse response) {
// Activate scheduler
run(request.getParameter("param1"))
...
}
The scheduler (or whatever performs the automated actions) should stop as soon as the user gets again to the same web page triggering the automated actions and should run in background not blocking any other code from execution (to be precise, I cannot simply put a while loop with Sys.sleep in the function mapped to the page URL request why the page should do other things)
Any help?
Consider using ScheduledExecutorService.scheduleAtFixedRate for this as the Spring scheduler are independent of any users' request (which you have already observed and noted in question).
You may use shutdownNow to terminate the scheduler once the users' session is no longer valid / a new request is received. To achieve this you could maintain cache of previous executor(s) with user id (or any relevant information) to identify the instance which should be invalidated.
As an alternative you could use Timer and TimerTask if more fine grained control is required (however not recommended as noted here)
There are two common ways of achieving this.
The first is to run your timer client-side, in JavaScript, and then runs an AJAX/websocket/whatever call. This has many advantages - once the user navigates away from your site, the timer will stop, and you're not tying up server-side resources so your application will scale much more cleanly. This is by far the cleanest solution if your timer is linked to a single user.
The second is to use a message queue; pop a message on the queue and have an asynchronous process checking those messages, ideally aggregating multiple client sessions in a single database request. You need to figure out how to detect sessions timing out and remove the message from the message queue.
This approach is best when your timer is looking at information that's not tightly connected to the current user.
I'm using Vaadin Flow (14.1.18) and my question is a very bizarre behavior I've faced.
I have added the following configs into my Spring Boot project's application.properties file.
// Expected behavior: Vaadin Client to send heartbeat to the server every second
vaadin.heartbeatInterval=1
// Expected Behavior: Vaadin Server to close Idle sessions after 3 seconds (3 rounds of failed heart beats)
vaadin.closeIdleSessions=true
I have checked these configs to be applied practically on runtime using below code
DeploymentConfiguration deployConf = VaadinSession.getCurrent().getConfiguration();
int hbi =deployConf.getHeartbeatInterval();
boolean killIdle = deployConf.isCloseIdleSessions();
logger.info("Deployment Config >> KillIdleSessions : {} -- HeartBeatInterval : {}", killIdle, hbi);
And I get the following result which shows my configs got applied
2020-03-05 23:16:01.015 INFO 19224 --- [nio-9200-exec-3]
com.package.sandbox.MainView : Deployment Config >> KillIdleSessions :
true -- HeartBeatInterval : 1
But, the problem is, during the runtime, it seems Vaadin is ignoring all these configs, and despite I close the browser (UI instance won't be there anymore to send heartbeats) the session stays open indefinitely and never get closed (or destroyed, in Vaadin's perspective).
The heartbeats are used to close other UIs in the session, it won't help in closing the last UI.
When the VaadinService has finished handling a request, it calls VaadinService#cleanupSession. This loops through all UIs in the session, and checks if the time passed since the last heartbeat is longer than three heartbeat intervals, in which case the UI is closed. The point of this is to clean up inactive UIs in the session, such as from closed tabs or refreshed windows.
When you close the last tab, the server will not receive any more requests for that session. As the cleanup code is run at the end of a request, it will not be triggered anymore. This prevents your last UI from being closed.
Instead, the session timeout comes into play. You can configure it with server.servlet.session.timeout, e.g. 120s or 2m. The embedded Tomcat has a reaper thread that is run once every minute, and it will close any inactive sessions. Note that with Spring, the minimum value for the session timeout is one minute.
If you leave a UI open but idle, the heartbeats will keep the session active, and prevent the session timeout handler form closing it. This is where closeIdleSessions comes into play. If it is set to true, after a request ends, Vaadin will check the last timestamp of a non-heartbeat request, and if the session timeout is exceeded, it will be closed by Vaadin.
So, in short
heartbeatInterval controls how quickly other inactive UIs in a session are closed, but does not affect the last UI.
closeIdleSessions controls whether or not heartbeats should prevent a session timing out for an otherwise idle UI.
Note: After changing values in application.properties, you might need an incognito window to test your changes, as the last session might've been serialized and re-used after a restart.
How to get loading time of each component of a page in CQ5 from server side.
Here as per my implementation we are getting longest time taking to load page from request.log file. But i need to get each component loading time of page from server side.
I found this link but this will work from client side:
http://www.wemblog.com/2014/05/how-to-find-component-load-time-on-page.html
You have to include logger for every component tag class call and provide stopwatch for entry and exit of the call.
Logger LOG = LoggerFactory.getLogger(classname.class);
StopWatch stopWatch = new StopWatch("new");
stopWatch.start();
stopWatch.stop();
Once you included this in your tag class you could able to find the time taken for each component in a particular page.
You can use putty for accessing your server log.
Starting from version AEM 6.0, there is OOTB feature to measure rendering time for each component on a page.
It is accessible through TouchUI, Developer mode.
However, it won't work if AEM is installed with run mode 'nosamplecontent'.
You can use the RequestProgressTracker, as explained in the Sling documentation
It's obtainable from SlingHttpServletRequest#getRequestProgressTracker. In order to get the timing stats for your components, you can use a Servlet Filter to execute the code on every request.
Whenever the filter is called:
Get the RequestProgressTracker from the request object
Call getMessages to obtain an iterator over a collection of request progress messages for the current request
Analyze the messages to find the resource types and timing information. Unfortunately, every message is only available as a String so you'll need to parse it to get the data.
Let's have a look at some example messages from the docs:
The last message is the kind we're looking for:
TIMER_END{103,/libs/sling/servlet/default/explorer/node.esp#0}
The number 103 is the number of milliseconds the script took to execute. The value after the comma is the script. You can tailor a regular expression to extract both values from every such message.
One of the projects I recently worked on used this approach to report on component performance. We had a neat dashboard in NewRelic with live stats on every component we built.
I am trying to set the write timeout in Cassandra with the Java drive. SocketOptions allows me to set a read and connect timeout but not a write timeout.
Does anyone knows the way to do this without changing the cassandra.yaml?
thanks
Altober
The name is misleading, but SocketOptions.getReadTimeoutMillis() applies to all requests from the driver to cassandra. You can think of it as a client-level timeout. If a response hasn't been returned by a cassandra node in that period of time an OperationTimeoutException will be raised and another node will be tried. Refer to the javadoc link above for more nuanced information about when the exception is raised to the client. Generally, you will want this timeout to be greater than your timeouts in cassandra.yaml, which is why 12 seconds is the default.
If you want to effectively manage timeouts at the client level, you can control this on a per query basis by using executeAsync along with a timed get on the ResultSetFuture to give up on the request after a period of time, i.e.:
ResultSet result = session.executeAsync("your query").get(300, TimeUnit.MILLISECONDS);
This will throw a TimeoutException if the request hasn't been completed in 300 ms.
In web.xml I've mentioned 5mins as the session time out.
Suppose if my request to load page with data from db taked morethan 5 mins what will happen.
Will the request get processed ? will the sessiong timeout get extended?
The session is attached with a timestamp generate on the server. This timestamp is used by the server to know if the session is timeout.
So when you'll access the session in this process or an other, if the timer is ended, the session will be out of date even if it is caused by a too long processing of the last request.
It will expire, as there is no communication happening between client and server. On the other hand, for these kind of long-running jobs, it is better to use some sort of async/batch technology, and let the client check results later.