Vaadin heartbeats not working on GraalVM native image (or lastAccessedTime is wrong)

I have a Vaadin application that I am compiling to a native Windows image using GraalVM. So far, everything is working however the client heartbeats either are not working or the last accessed time is not being updated in the session.

For a VaadinSession, I am using the following to get time since last request:

long lastRequest = System.currentTimeMillis() - session.getSession().getLastAccessedTime();

This works as expected running the application as a jar with a heartbeatInterval of 5:

3AC2865CDF8923C11EC4FD90DBCD436B: 429ms
3AC2865CDF8923C11EC4FD90DBCD436B: 1435ms
3AC2865CDF8923C11EC4FD90DBCD436B: 2435ms
3AC2865CDF8923C11EC4FD90DBCD436B: 3434ms
3AC2865CDF8923C11EC4FD90DBCD436B: 4430ms
3AC2865CDF8923C11EC4FD90DBCD436B: 558ms
3AC2865CDF8923C11EC4FD90DBCD436B: 1555ms
3AC2865CDF8923C11EC4FD90DBCD436B: 2567ms
3AC2865CDF8923C11EC4FD90DBCD436B: 3568ms
3AC2865CDF8923C11EC4FD90DBCD436B: 4568ms
3AC2865CDF8923C11EC4FD90DBCD436B: 560ms
3AC2865CDF8923C11EC4FD90DBCD436B: 1554ms
3AC2865CDF8923C11EC4FD90DBCD436B: 2553ms

However, if I run the same application with the same properties instead compiled using GraalVM, the last accessed time or heartbeat is not correct:

70AA6435EBF71A07D66325BD4F72D207: 240ms
70AA6435EBF71A07D66325BD4F72D207: 1239ms
70AA6435EBF71A07D66325BD4F72D207: 2238ms
70AA6435EBF71A07D66325BD4F72D207: 3241ms
70AA6435EBF71A07D66325BD4F72D207: 4244ms
70AA6435EBF71A07D66325BD4F72D207: 5246ms
70AA6435EBF71A07D66325BD4F72D207: 6244ms
70AA6435EBF71A07D66325BD4F72D207: 7246ms
70AA6435EBF71A07D66325BD4F72D207: 8233ms
70AA6435EBF71A07D66325BD4F72D207: 9238ms
70AA6435EBF71A07D66325BD4F72D207: 10246ms
70AA6435EBF71A07D66325BD4F72D207: 11242ms
70AA6435EBF71A07D66325BD4F72D207: 12245ms

My intent is to close sessions quickly after a user closes a browser without explicitly logging out, but the end result is that the sessions are getting closed even if a user has the browser open because the server is not recognizing the heartbeats. The reason for wanting to close the sessions is that the software is licensed by number of active sessions so I don’t want a dead session to sit around counting toward the limit when another user could potentially login instead.

Use a fresh version of Vaadin and forget the heartbeat interval. UIs will be closed right after you close your browser window (or navigate away).

I am using 24.3.10. Is there a newer released version I should use?

I see the session has a getUIs() method, I will try using that instead of relying on the last accessed time. Currently, the session itself is not closing when a browser is closed and that is what I was basing it on.

With that version UIs should be closed perfectly. I think I wrote the patch last summer (uses so called Beacon API in the browser to notify of closed browser window). Maybe there is some issue with native images that affects also this feature :thinking: I’m not using native builds myself, way too much hassle for my taste to save couple of megabytes of ram…

It looks like it’s working properly by checking the number of UIs in the session. Thanks for the help.

Excellent! I think we didn’t properly market this nice new feature. It can also cause huge memory savings in certain type of Vaadin apps (lot of users, short sessions).

Do you know if between the login page and my AppLayout there will be 0 UIs in the session? I think I am hitting a race condition where during the login process there are 0 UIs and rarely I can get kicked back to the login page due to invalidated session immediately after login. My login view is not part of the main AppLayout.

I think I resolved the problem using a combination of the number of UIs and the last request time. Basically, if there are 0 UIs and last request time is low then user is between pages (login, refresh) but if it’s high then they must have closed the browser.

I don’t know for sure (without launching a debugger), but I could guess there might be a tiny delay with the “beacon request” browser is making.

I don’t now understand why you need to fiddle with the last request time at all as/if the beacon request is properly working. Detach listener would do the same with cleaner code :thinking:

I don’t think I’m clear on this. Do you mean to add a detach listener to each UI? If I do this and have the listener see if this UI is the only one for the session and close the session if so, how do I account for the times when the user refreshes the page or going from the login page to the main page? From what I can see, this is also triggering the detach listener. Is there something else I should be checking?

I was more like thinking to hook the listener to the relevant views (or overriding onDetach) on them. But don’t know exactly how your licenses are calclulated, so maybe i was thinking in wrong way. Maybe just configuring the http session timeout to something rather short would be enough :thinking:

I think this has the same problem as above. If I am on the main app layout and refresh the page, the onDetach is called there as well and I would have to differentiate between this refresh and a user actually closing the session. Unless you know a solution to that problem, I think what I have is working well enough. The sessions are cleared out within a few seconds of the last UI being removed from the session.

As for setting the session timeout, are you referring to the setMaxInactiveInterval method on the WrappedSession? I’ll check that out and see if I can use that. I think there’s also the server.servlet.session.timeout property but I believe I already tried that and something about it didn’t work which eventually led me to my initial problem with GraalVM.