Vaadin session setMaxInactiveInterval UI response inconsistant
Asked Answered
C

3

12

I have set the max inactive interval for Vaadin session as following.

VaadinSession.getCurrent().getSession().setMaxInactiveInterval(60); 

Added a session destroy listener as following for testing.

    servletService.addSessionDestroyListener(new SessionDestroyListener() {
    public void sessionDestroy(SessionDestroyEvent event) {
        System.out.println("SESSION TIMEOUT");
    }
});

This listener get called at the desired time on the server side. However I cannot see "Session Expired" message on the browser side at the same time. Normally it gets displayed between 4th and 5th minutes. Is there a way to get both of these at the same time in a consistent manner.

Also note that we are not using push and it is not an option for us at the moment.

Doing client side polling will reset last active time of the sessions and can keep the session active forever if poll interval is lesser than maxInactiveInterval.

Croom answered 1/9, 2015 at 5:23 Comment(0)
C
1

Following solution worked for me in this scenario of not having @Push enabled as well as without any custom js widgets. First set maxInactiveInterval as following in the main class. Showing only the code related to this solution.

    public class MyApplication extends UI { 
      @Override
        protected void init(VaadinRequest request) {
VaadinSession.getCurrent().getSession().setMaxInactiveInterval(sessionTimeout);
    }

    }

We have to default session expired message as following. This has been suggested in a Vaadin forum as a solution and it said it should work within 15 seconds of session timeout.

    public class CustomInitServlet extends VaadinServlet {
         getService().setSystemMessagesProvider(
                new SystemMessagesProvider() {
                    @Override
                    public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo) {
                        CustomizedSystemMessages customizedSystemMessages = new CustomizedSystemMessages();
                        customizedSystemMessages.setSessionExpiredMessage(null);
                        customizedSystemMessages.setSessionExpiredCaption(null);
                        customizedSystemMessages.setSessionExpiredNotificationEnabled(true);
                        return customizedSystemMessages;
                    }
                });


// other code
}

Then in the web.xml added high heartbeat interval which will be higher than the maxInactiveInterval.

<context-param>
    <param-name>heartbeatInterval</param-name>
    <param-value>1200</param-value>
</context-param>
Croom answered 10/9, 2015 at 9:16 Comment(0)
V
5

Vaadin application keeps Client Side and Server Side communication during session life-cycle. There is parameter calls heartbeatInterval with default value 5 mins (300s). So it is means that every 5 mins Client Side ask Server if session still alive. That is why, when Session is destroyed you see message in Console and only after some period of time you see Session Expired message in a Browser.

You can change heartbeatInterval property and set smaller value (in seconds), but remember that you need to set closeIdleSessions=true explicitly as well. In example below I set this value to 1 second.

@VaadinServletConfiguration(heartbeatInterval=1, closeIdleSessions=true, productionMode = false, ui = MyUI.class)
    public static class Servlet extends VaadinServlet {
    }
Veinlet answered 4/9, 2015 at 10:53 Comment(7)
You can also modify this interval in the web.xml deployment descriptor :)Kirkuk
@Taras Klym , it require three missed heat-beats on the server side to invalidate the session. In the default case it take 15 minutes. Approach mentioned in the question has been used, since heartbeatinterval is not configurable after deployment.Croom
@Don, you almost right, but heart-beat has two functions: the first one is invalidate session on Server Side if user close tab with application or browser after 3 missed heart-beat (by default around 15mins) and second one - notify Client Side that session on the Server has been closed on the next heart-beat (by default around 5mins). In the problem that you describe you have situation #2. Session has been destroyed on the Server and show message with next heart-beat.Veinlet
@Taras Klym , yah in that case what you mean is that user will not be notified at the same time on the client side. Which is the issue I'm facing.Croom
@Don exactly, that is why if you change the heartBeatInterval to smaller number of seconds, you will decrease this gap. If you put heartBeatInterval to 1 second, you will notify User in the same time when Session is destroyed on the Server.Veinlet
@Taras Klym , What about the server hit if it is reduced to such a low value? I don't think that is a good option.Croom
Small value of heartBeat should not be a problem. Your idea is to keep sync Client side with Server side. So there are 3 options. 1. Exactly what you need is HeardBeatInterval value that was designed to keep synchronized Client and Server, track session. 2. Like option - Push. 3. Option with extra work - polling you can set with setPollInterval option. But you need filtered this polling request with extra filter and track session timeout interval manualy. Polling has no any advantages over heartBeat in your situation. heardBeat is best for you or Push like a option in the future.Veinlet
K
3

The problem :

Your session is invalidated on the server side, everything is good. But the problem is that your client is never notified of this event. You have to do an interaction with the server to get a Session Expired message, like pressing the button, refreshing the page, etc...

How to fix this?

To fix this, you have some solutions:

  • Use @Push annotation see Documentation
  • Force client-side refresh using getPage().reload()
  • Change nothing and your session timeout will appear on next Client-Side action
  • Implement a "Session lookup" on client side to watch every X seconds if the session is still valid, if it is expired, simply call Page.getCurrent.reload() from client side.

Be careful with @Push

Depending on the application server you are Using, you may need to update it to support @Push (I had to with tomcat7, because tomcat7 doesn't support WebSocket)

Kirkuk answered 3/9, 2015 at 9:45 Comment(7)
thanks for the answer, Yes I know that the problem is client side is not get notified. However we are doing the app without Push. Changing nothing is also not an option since it looks like session has not expired. Forcing a page refresh looks like an option. But I think it will not work with a destroyed session, since there is no such this as "Page" since there is no client session. Correct me if I'm wrong.Croom
Using Page.getCurrent().reload() (corrected the method name in my answer) should refresh the client page because even if the client Session is expired, the Page object related to it should still exist. In my opinion, without Push you can't notify client properly. I added another solution I just found in case it can solve your problem.Kirkuk
yes I also thought of doing polling on the client side to see if the sever is still alive. But it won't work since polling server will reset the last active time of the session and because of that session will never timeout.Croom
By checking if session was valid, I meant you request a boolean on server to know if session is valid, not requesting the session itself from the server.Kirkuk
Yah I know, but to check that we have to send a request from the client side to server. Then the session get active just because of the poll. For this to work, poll interval must be higher than the session timeout time.Croom
Awarded you the bounty considering the coverage of your answer, how ever this was solved as in my following answer.Croom
Thank you :) hope it will help some other devs on VAADIN ;)Kirkuk
C
1

Following solution worked for me in this scenario of not having @Push enabled as well as without any custom js widgets. First set maxInactiveInterval as following in the main class. Showing only the code related to this solution.

    public class MyApplication extends UI { 
      @Override
        protected void init(VaadinRequest request) {
VaadinSession.getCurrent().getSession().setMaxInactiveInterval(sessionTimeout);
    }

    }

We have to default session expired message as following. This has been suggested in a Vaadin forum as a solution and it said it should work within 15 seconds of session timeout.

    public class CustomInitServlet extends VaadinServlet {
         getService().setSystemMessagesProvider(
                new SystemMessagesProvider() {
                    @Override
                    public SystemMessages getSystemMessages(SystemMessagesInfo systemMessagesInfo) {
                        CustomizedSystemMessages customizedSystemMessages = new CustomizedSystemMessages();
                        customizedSystemMessages.setSessionExpiredMessage(null);
                        customizedSystemMessages.setSessionExpiredCaption(null);
                        customizedSystemMessages.setSessionExpiredNotificationEnabled(true);
                        return customizedSystemMessages;
                    }
                });


// other code
}

Then in the web.xml added high heartbeat interval which will be higher than the maxInactiveInterval.

<context-param>
    <param-name>heartbeatInterval</param-name>
    <param-value>1200</param-value>
</context-param>
Croom answered 10/9, 2015 at 9:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.