request.getSession() returns a different object for each request - Undertow's session object is the object retrieved by request.getSession()

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

request.getSession() returns a different object for each request - Undertow's session object is the object retrieved by request.getSession()

Eric B
I'm migrating a legacy (circa 2005) n-tier JBoss 4 application to run in Wildfly 10.  It was a struggle, but got pretty much everything done.  We've been trying as hard as possible not to refactor logic/code/etc except in the cases where it is simply no longer compatible.  The goal was to get the application working "as-is" in WF, then start tackling the job of breaking it apart and refactoring it into proper pieces.

The problem I have run into now is regarding session management.  The application was designed to run on multiple nodes, but in standalone instances - ie: there is no shared memory, nor any distributed caches.  So I'm trying to get my WF10 application to follow the same pattern (even though I realize all this exists in WF10 out of the box with Infinispan/etc).

One of the requirements is to only have a single session active for a user at any time in the "cluster".  The JB4 application accomplished this by maintaining a local cache (HashMap) of session objects keyed by username.  When a user logs into any node, a JMS message is broadcast to all the nodes to invalidate any session belonging to that user.  The listener on each node then searches in his cache for a matching user/session object and does a session.invalidate().  Some extra logic is used for WeakReferences for the session objects (in case the session is destroyed by some other flow in the container).

As ugly as the solution was, we've tried to follow the same pattern under WF10.  But this is failing in many different ways and reinforces my belief that it isn't the right approach.  However, I would like to understand how/why this is failing.

My server configuration is using a <local-cache> for my "web" cache.  So to me this means it is only local to the machine.  But:

1) on any specific node, request.getSession() returns a different object for each request.  The sessionId() remains the same, but the actual object ID changes.  This implies that it is a different representation of the session object.

2) if I persist a local copy of the HttpSession object between requests (ex: in a static map) and invalidate the session using the persisted object, my request.getSession() object is not updated (ex: the invalid flag is still set to false), but the session is dead.  Trying to call request.getSession().invalidate() throws IllegalStateException as do calls to request.getSession().set/getAttribute()

3) over time, my JVM will actually crash with an EXCEPTION_ACCESS_VIOLATION in a GC process.  This always seems to correlate with a thread that is trying to do some session invalidation via the persisted session copy.


Is anyone able to explain this behaviour?  Why is the session object always different between requests?  Shouldn't it be the same request?  What is Undertow doing with the session objects between requests?  Is the Undertow object being passivated in some way and my attempt to invalidate if from within my cached version causing this kind of access violation?  Is my cached object referencing memory that has been cleared by the GC (ex: does the request.getSession() object only a WeakReference to the actual Undertow object)?


Finally, what would the recommended approach be to doing something like this?  Using a distributed web-cache is unfortunately not an option at the moment.  So give that, is there some way to access the Undertow session manager directly?

Thanks for any insight.  I thought we had a functional solution but in production (under real load), the intermittent JVM crashes are telling me that our solution is broken.

Eric

_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: request.getSession() returns a different object for each request - Undertow's session object is the object retrieved by request.getSession()

Stuart Douglas


On Sat, Dec 9, 2017 at 3:04 PM, Eric B <[hidden email]> wrote:
I'm migrating a legacy (circa 2005) n-tier JBoss 4 application to run in Wildfly 10.  It was a struggle, but got pretty much everything done.  We've been trying as hard as possible not to refactor logic/code/etc except in the cases where it is simply no longer compatible.  The goal was to get the application working "as-is" in WF, then start tackling the job of breaking it apart and refactoring it into proper pieces.

The problem I have run into now is regarding session management.  The application was designed to run on multiple nodes, but in standalone instances - ie: there is no shared memory, nor any distributed caches.  So I'm trying to get my WF10 application to follow the same pattern (even though I realize all this exists in WF10 out of the box with Infinispan/etc).

One of the requirements is to only have a single session active for a user at any time in the "cluster".  The JB4 application accomplished this by maintaining a local cache (HashMap) of session objects keyed by username.  When a user logs into any node, a JMS message is broadcast to all the nodes to invalidate any session belonging to that user.  The listener on each node then searches in his cache for a matching user/session object and does a session.invalidate().  Some extra logic is used for WeakReferences for the session objects (in case the session is destroyed by some other flow in the container).

As ugly as the solution was, we've tried to follow the same pattern under WF10.  But this is failing in many different ways and reinforces my belief that it isn't the right approach.  However, I would like to understand how/why this is failing.

My server configuration is using a <local-cache> for my "web" cache.  So to me this means it is only local to the machine.  But:

1) on any specific node, request.getSession() returns a different object for each request.  The sessionId() remains the same, but the actual object ID changes.  This implies that it is a different representation of the session object.

Undertow returns a different facade for each request. Undertow uses its internal representation of a session (io.undertow.server.session.Session) that is stored in the session manager, and wraps a facade around it (io.undertow.servlet.spec.HttpSessionImpl) that implements Servlet semantics.
 

2) if I persist a local copy of the HttpSession object between requests (ex: in a static map) and invalidate the session using the persisted object, my request.getSession() object is not updated (ex: the invalid flag is still set to false), but the session is dead.  Trying to call request.getSession().invalidate() throws IllegalStateException as do calls to request.getSession().set/getAttribute()

I guess this could be considered a bug in that isNew will not throw an IllegalStateException, which is the only place that the invalid flag is used without also consulting the underlying session, but you sound as if you expect the session to still work after it has been invalidated?

There is no requirement that the same session is represented by a single java object, and especially it in a distributed environment this is not possible. Even though we could keep the same facade around for all requests this can encourage people to write apps that rely on this behaviour, and also increases the likelihood that the facade will become tenured and require a full GC to be reclaimed. 
 

3) over time, my JVM will actually crash with an EXCEPTION_ACCESS_VIOLATION in a GC process.  This always seems to correlate with a thread that is trying to do some session invalidation via the persisted session copy.

This is a JVM bug. Which JVM are you using?

To implement this I would remove the WeakReference which will not work with Undertow's session management strategy, and instead register a listener to remove the session from the local map when it is invalidated. If you really want to access the underlying Undertow session you can call io.undertow.servlet.spec.HttpSessionImpl#getSession() to return the Underlying Undertow session, although it should not be necessary.

Stuart




Is anyone able to explain this behaviour?  Why is the session object always different between requests?  Shouldn't it be the same request?  What is Undertow doing with the session objects between requests?  Is the Undertow object being passivated in some way and my attempt to invalidate if from within my cached version causing this kind of access violation?  Is my cached object referencing memory that has been cleared by the GC (ex: does the request.getSession() object only a WeakReference to the actual Undertow object)?


Finally, what would the recommended approach be to doing something like this?  Using a distributed web-cache is unfortunately not an option at the moment.  So give that, is there some way to access the Undertow session manager directly?

Thanks for any insight.  I thought we had a functional solution but in production (under real load), the intermittent JVM crashes are telling me that our solution is broken.

Eric

_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev


_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: request.getSession() returns a different object for each request - Undertow's session object is the object retrieved by request.getSession()

Eric B
Hi Stuart, 

Thanks for the reply.  A few followup questions if you don't mind.


1) on any specific node, request.getSession() returns a different object for each request.  The sessionId() remains the same, but the actual object ID changes.  This implies that it is a different representation of the session object.

Undertow returns a different facade for each request. Undertow uses its internal representation of a session (io.undertow.server.session.Session) that is stored in the session manager, and wraps a facade around it (io.undertow.servlet.spec.HttpSessionImpl) that implements Servlet semantics.

That's what I had assumed as well, based on the behaviour I had noticed.  Thanks for confirming.
 
 

2) if I persist a local copy of the HttpSession object between requests (ex: in a static map) and invalidate the session using the persisted object, my request.getSession() object is not updated (ex: the invalid flag is still set to false), but the session is dead.  Trying to call request.getSession().invalidate() throws IllegalStateException as do calls to request.getSession().set/getAttribute()

I guess this could be considered a bug in that isNew will not throw an IllegalStateException, which is the only place that the invalid flag is used without also consulting the underlying session, but you sound as if you expect the session to still work after it has been invalidated?

No - quite the opposite actually.  I'm expecting that all session objects to react the same after it has been invalidated.  If I use one of the facades from a prior request to invalidate the session, I would expect that every facade would respect the same state.  For instance, if I do the following:

Request 1:

// store a copy of the session object to be available in a later request
static Session cachedSessionObj = request.getSession();


Request 2:

// invalidate the session from the cached object
cachedSessoinObject.invalidate();

// get a new session
Session newSession = request.getSession();


I would expect that cachedSessionObj.getId() != newSessoin.getId().

However, the request.getSession() doesn't get a new session object.  Rather it still returns the old (now invalidated) session object.  So any logic that is dependent on having a fresh session object fails (since the session object is returned is actually the invalidated session).

 
There is no requirement that the same session is represented by a single java object, and especially it in a distributed environment this is not possible. Even though we could keep the same facade around for all requests this can encourage people to write apps that rely on this behaviour, and also increases the likelihood that the facade will become tenured and require a full GC to be reclaimed. 

Understood.
 

3) over time, my JVM will actually crash with an EXCEPTION_ACCESS_VIOLATION in a GC process.  This always seems to correlate with a thread that is trying to do some session invalidation via the persisted session copy.

This is a JVM bug. Which JVM are you using?
I'm running Oracle Hotspot Java 8x64 on a Windows platform (server 2016).  I've tried with both patch 131 and 151, and both exhibit the same behaviour.  

To implement this I would remove the WeakReference which will not work with Undertow's session management strategy, and instead register a listener to remove the session from the local map when it is invalidated. If you really want to access the underlying Undertow session you can call io.undertow.servlet.spec.HttpSessionImpl#getSession() to return the Underlying Undertow session, although it should not be necessary.

I've already removed the WeakReference as soon as I noticed that the session facade returned by Undertow changed at each request.  I am using a session listener to remove it from the local map when it is invalidated, but I need an ability for an JMS listener to be able to invalidate a session object based on an id it receives.

How can I access Undertow's SessionManager from within my application?  Is there any way I can retrieve it from the CDI?  I tried adding the io.undertow.core module to my jboss-deployment-structure.xml, but yet I can't access it via injection or via: CDI.current().getBeanManager().getBeans(SessionManager.class); in both cases it is unable to find the SessionManager class.  Is there some other way I can access it/retrieve it from within my application?  


Thanks,

Eric



 
Is anyone able to explain this behaviour?  Why is the session object always different between requests?  Shouldn't it be the same request?  What is Undertow doing with the session objects between requests?  Is the Undertow object being passivated in some way and my attempt to invalidate if from within my cached version causing this kind of access violation?  Is my cached object referencing memory that has been cleared by the GC (ex: does the request.getSession() object only a WeakReference to the actual Undertow object)?


Finally, what would the recommended approach be to doing something like this?  Using a distributed web-cache is unfortunately not an option at the moment.  So give that, is there some way to access the Undertow session manager directly?

Thanks for any insight.  I thought we had a functional solution but in production (under real load), the intermittent JVM crashes are telling me that our solution is broken.

Eric

_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev



_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev
Reply | Threaded
Open this post in threaded view
|

Re: request.getSession() returns a different object for each request - Undertow's session object is the object retrieved by request.getSession()

Stuart Douglas


On Mon, Dec 11, 2017 at 3:01 PM, Eric B <[hidden email]> wrote:
Hi Stuart, 

Thanks for the reply.  A few followup questions if you don't mind.


1) on any specific node, request.getSession() returns a different object for each request.  The sessionId() remains the same, but the actual object ID changes.  This implies that it is a different representation of the session object.

Undertow returns a different facade for each request. Undertow uses its internal representation of a session (io.undertow.server.session.Session) that is stored in the session manager, and wraps a facade around it (io.undertow.servlet.spec.HttpSessionImpl) that implements Servlet semantics.

That's what I had assumed as well, based on the behaviour I had noticed.  Thanks for confirming.
 
 

2) if I persist a local copy of the HttpSession object between requests (ex: in a static map) and invalidate the session using the persisted object, my request.getSession() object is not updated (ex: the invalid flag is still set to false), but the session is dead.  Trying to call request.getSession().invalidate() throws IllegalStateException as do calls to request.getSession().set/getAttribute()

I guess this could be considered a bug in that isNew will not throw an IllegalStateException, which is the only place that the invalid flag is used without also consulting the underlying session, but you sound as if you expect the session to still work after it has been invalidated?

No - quite the opposite actually.  I'm expecting that all session objects to react the same after it has been invalidated.  If I use one of the facades from a prior request to invalidate the session, I would expect that every facade would respect the same state.  For instance, if I do the following:

Request 1:

// store a copy of the session object to be available in a later request
static Session cachedSessionObj = request.getSession();


Request 2:

// invalidate the session from the cached object
cachedSessoinObject.invalidate();

// get a new session
Session newSession = request.getSession();


I would expect that cachedSessionObj.getId() != newSessoin.getId().

However, the request.getSession() doesn't get a new session object.  Rather it still returns the old (now invalidated) session object.  So any logic that is dependent on having a fresh session object fails (since the session object is returned is actually the invalidated session).

Once a session has been assigned to the request it does not change. This is a bit of a grey area.
 

 
There is no requirement that the same session is represented by a single java object, and especially it in a distributed environment this is not possible. Even though we could keep the same facade around for all requests this can encourage people to write apps that rely on this behaviour, and also increases the likelihood that the facade will become tenured and require a full GC to be reclaimed. 

Understood.
 

3) over time, my JVM will actually crash with an EXCEPTION_ACCESS_VIOLATION in a GC process.  This always seems to correlate with a thread that is trying to do some session invalidation via the persisted session copy.

This is a JVM bug. Which JVM are you using?
I'm running Oracle Hotspot Java 8x64 on a Windows platform (server 2016).  I've tried with both patch 131 and 151, and both exhibit the same behaviour.  

I would report it to Oracle. 
 

To implement this I would remove the WeakReference which will not work with Undertow's session management strategy, and instead register a listener to remove the session from the local map when it is invalidated. If you really want to access the underlying Undertow session you can call io.undertow.servlet.spec.HttpSessionImpl#getSession() to return the Underlying Undertow session, although it should not be necessary.

I've already removed the WeakReference as soon as I noticed that the session facade returned by Undertow changed at each request.  I am using a session listener to remove it from the local map when it is invalidated, but I need an ability for an JMS listener to be able to invalidate a session object based on an id it receives.

How can I access Undertow's SessionManager from within my application?  Is there any way I can retrieve it from the CDI?  I tried adding the io.undertow.core module to my jboss-deployment-structure.xml, but yet I can't access it via injection or via: CDI.current().getBeanManager().getBeans(SessionManager.class); in both cases it is unable to find the SessionManager class.  Is there some other way I can access it/retrieve it from within my application?  

You can do io.undertow.servlet.spec.ServletContextImpl#getSession(java.lang.String) to get an arbitrary session.

If you want the actual SessionManager you would need to call io.undertow.servlet.spec.ServletContextImpl#getDeployment().getSessionManager().

Stuart
 


Thanks,

Eric



 
Is anyone able to explain this behaviour?  Why is the session object always different between requests?  Shouldn't it be the same request?  What is Undertow doing with the session objects between requests?  Is the Undertow object being passivated in some way and my attempt to invalidate if from within my cached version causing this kind of access violation?  Is my cached object referencing memory that has been cleared by the GC (ex: does the request.getSession() object only a WeakReference to the actual Undertow object)?


Finally, what would the recommended approach be to doing something like this?  Using a distributed web-cache is unfortunately not an option at the moment.  So give that, is there some way to access the Undertow session manager directly?

Thanks for any insight.  I thought we had a functional solution but in production (under real load), the intermittent JVM crashes are telling me that our solution is broken.

Eric

_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev




_______________________________________________
wildfly-dev mailing list
[hidden email]
https://lists.jboss.org/mailman/listinfo/wildfly-dev