A JEE application I am looking at sometimes - no idea why it happens - goes into this wel exception.
WELD-001304: More than one context active for scope type javax.enterprise.context.SessionScoped
at org.jboss.weld.manager.BeanManagerImpl.internalGetContext(BeanManagerImpl.java:678)
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:645)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:89)
at org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:164)
at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:87)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:131)
at org.apache.deltaspike.core.impl.scope.window.WindowBeanHolder$Proxy$_$$_WeldClientProxy.getContextualStorage(Unknown Source)
at org.apache.deltaspike.core.impl.scope.window.WindowContextImpl.getContextualStorage(WindowContextImpl.java:119)
at org.apache.deltaspike.core.util.context.AbstractContext.get(AbstractContext.java:78)
at org.jboss.weld.contexts.PassivatingContextWrapper$AbstractPassivatingContextWrapper.get(PassivatingContextWrapper.java:70)
at org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:89)
at org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:63)
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:87)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.getInstance(ProxyMethodHandler.java:131)
at org.apache.deltaspike.core.impl.scope.viewaccess.ViewAccessViewHistory$Proxy$_$$_WeldClientProxy.getLastView(Unknown Source)
at org.apache.deltaspike.core.impl.scope.viewaccess.ViewAccessContext.close(ViewAccessContext.java:131)
at org.apache.deltaspike.core.impl.scope.viewaccess.ViewAccessContext.onProcessingViewFinished(ViewAccessContext.java:119)
at org.apache.deltaspike.jsf.impl.listener.request.DeltaSpikeLifecycleWrapper.render(DeltaSpikeLifecycleWrapper.java:118)
at javax.faces.lifecycle.LifecycleWrapper.render(LifecycleWrapper.java:92)
at org.apache.deltaspike.jsf.impl.listener.request.JsfClientWindowAwareLifecycleWrapper.render(JsfClientWindowAwareLifecycleWrapper.java:160)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:659)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
It is not clear why this is happening. And the side effects are not always the same. Some times when this situation happens, you really need to restart the server, eve if you try to loging in incognito mode with a different browser. It is as if the BeanManager from WELD has become completely toasted.
This error is coming most often when you sleep your computer and the next day you start interacting with the application. But interesting enough, this is also happening quite often if I start triggering selinum tests. Have no idea why the selenium testing would exacerbate the exception.
What I have seen now by putting a break point, is that we have WELD trying to resolve some injection point annotations. At some point, one of the injeaction points it wants to resolve is a:
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:87)
It is doing a
T existingInstance = ContextualInstance.getIfExists(bean, manager);
Where the Managed Bean
parameter bean = [class org.apache.deltaspike.core.impl.scope.window.WindowBeanHolder] with qualifiers [@Any @Default]
It is tring to resolve the bean injext:
[[BackedAnnotatedField] @Inject private org.apache.deltaspike.core.impl.scope.window.WindowBeanHolder.windowContextQuotaHandler]
Into the bean:
Managed Bean [class org.apache.deltaspike.jsf.impl.scope.window.JsfWindowContextQuotaHandler] with qualifiers [@Any @Default]
This window bean holder (could be any other bean I believe, it is irrelevant) is annotated with the session scoped annotation:
@SessionScoped
public class WindowBeanHolder extends AbstractBeanHolder<String>
{
And the system then breaks because the wildfly beanmanager impl, when it enter the logic of returning the SessionScoped context at line 678:
private Context internalGetContext(Class<? extends Annotation> scopeType) {
Context activeContext = null;
final List<Context> ctx = contexts.get(scopeType);
if (ctx == null) {
return null;
}
for (Context context : ctx) {
if (context.isActive()) {
if (activeContext == null) {
activeContext = context;
} else {
throw BeanManagerLogger.LOG.duplicateActiveContexts(scopeType.getName());
}
}
}
return activeContext;
}
This BeanManagerImpl code will not be happy with the fact that apparently a two SessionScopedContexts are at the same active.
In this code fragment what I see with the debugger is that the contexts variable is holding the following 3 session scoped contexts: [ org.jboss.weld.contexts.bound.BoundSessionContextImpl@136b5782, org.jboss.weld.module.web.context.http.HttpSessionContextImpl@6ef334ee, org.jboss.weld.module.web.context.http.HttpSessionDestructionContext@37a5a86e ]
The first ACTIVE CONTEXT found was:
oactiveContext = rg.jboss.weld.module.web.context.http.HttpSessionContextImpl@6ef334ee
The second CONTEXT we have is:
context = org.jboss.weld.module.web.context.http.HttpSessionDestructionContext@37a5a86e
That means for whatever reason, in my seystem both the HttpSessionContextImpl and the HttpSessionDestructionContext.
I am clueless is a to how these contexts are being toggled between ACTIVE/INACTIVE, if this is supposed to be "ThreadContext" specific flag that for a given thread the session scoped is corrupted but other threads with differ JESSESIONID cookie would start in an appropriate virgin state. where only one session context is active.
Any ideas of what could be causing this?
Note, widlfly 13.0.Final uses:
<dependency>
<groupId>org.jboss.weld</groupId>
<artifactId>weld-core-impl</artifactId>
<version>3.0.4.Final</version>
<scope>provided</scope>
</dependency>
Many thanks
The issue is now understood.
This duplicate active session scoped context is caused by two factors. First an application specific problem that only occurs in widlfy and not in weblogic.
Second a wildfly problem (this one is debatable it is a matter of opinion, but I believe wildfly should be more robust here).
The first problem. Whenever an HTTP session becomes expired in wildfly / undertow, a session reaper process will kick in to terminate the session. Every application server has its own process of doing this. The following stack trace snippet depicts what is going on when a session is being destoryed in wildfly.
The above stack trace is important for two reasons. One it gives you an idea of how underdow decides to initiate killing of sessions that have timed out. Second it is showing you a very real possibility on any application - it can break when handling a session destruction event. The code that is blowing up the stack trace above works perfectly fine in weblogic, because we have a RequestScope active. The code in wildfly is breaking because there is no request scope active. So I have not fixed the code blowing up in the stack trace above yet because I wanted to find a hack to get myself out of the problem that was reported here - since this could happen agian in the future very easily. So for me the request scope exception is irrelevant, what is relevat are the side effects that come after.
It is also very important to understand that before the code that is blowing up above was called something very important took place. Namely the activation of what will be in the future the SECOND / DUPLICATION session scope context. Please look at the stack trace that I will put bellow. This stack trace takes place whenever UNDERTOW decides to initiate killing of sessions. When this happens wildfly comes int and decides to activate the very special session scope context implementation that is used outside of HTTP requests.
This stack trace here is critical to understand. So normally, on what we can call an happy HTTP request, widlfly will activate the following session scope context class.
But as shown above, when it is time to kill of an http session, then instead it activates that other implementation class of a session scope the. The
So until here is the story clear? Let us summarize until here.
(a) We have our application running happy (b) We close our browser window and we let the http session timeout (c) When undertow kills of the http session wildfly will acttivate the context HttpSessionDestructionContext (d) Our application speific session listener that is curious about ending sessions will blow up because the request scope context is not active
(e) ... I suppose the story finishes up very badly, because wildfly would most likely have some nice class or logic to in the end of proper session termination to deactivate the HttpSessionDestructionContext but whatever this logic is and whatever makes it gets triggered, for this application it will NEVER get triggered.
So what are we left with at this point? With a very subtle bug. We finally have a very corrupted thread. Whatever thread undertow used to kill of the session is now forever doomed to not support any more the session scoped context. Why? Because when you look at the implementation of these session contexts, you will see their state of being ative or not active is a THREAD LOCAL variable. What this means is for as long as this thread lives, the state it had fro the previous run will remain.
And here is where Wildfly is having a problem, in my opinion.
Widlfly could either have a "pre-emptive" cleanup logic that tries to make sure that before a thread is used to handover a request the thread local variables are cleaned up to avoid going on ahead with a dirty thread.
Or it would need to have some sort of resilience mechanism to make sure that when it activates a scope in the context of a running thread, before the thread finishes well or bad, that the scope is ultimately deactivated.
Ok.
To finalize. So now we have an application that blew up and as reward this applicaton now has one thread that is toasted. This issue is normally very difficult to reproduce because you normally do not have a very low timeout. So you have the feeling that this issue comes when you leave your applicaton server running for extended period time. Like you go home, put your computer to sleep and the next morning everything is blowing up (because all of your http sesisons have timed out since then). The best way to make this issue reproducible, is to go t your standalone.xml and set it up like this:
You set the timeout of a session to run every minute. Then with chrome you just open an icognito window loging to your application to get the JESSIONID created and close the window. Open a different iconito window login again and close again. Repeat this for many sessions.
Then in parallel, what you can do as well, is make sure that you set a DEBUG BREAKPOINT on the
Put the break point on the method:
Put in there the following breakpoint condition:
What this break point will allow you to do is to make sure that when UNDERTOW starts killing of your sessions, you block the thread and that forces the killing process of the sessions to go over multiple different threds. The larger the number of different threads that have been used to terminate sessions, the more threads you have corrupted, the more likely you are to re-use the thread in the future in a normal http request that will blow up with this error. Essentially, you are just simulating what in a normal production server might take hours to happen. In a productive server a session can be active for many hours if a user is active, unitl he goes home or whatever. And the next day is when you start having threads in your thread pool that are unsuable.
Ok to finalize. Soon I will be fixing that code that wsa breaking due to the lack request scope context. But before that, I want to make sure i am somehow able to heal my widlfly threads in case in the future this situation happes again.
To do this I am using a servlet listener as shown bellow. (the usage of listener and helper as separate classes has to do with now having the WAR file blow up when you try to deploy on weblogic and weblogic might complain it has no idea of what this org.jboss.weld.module.web.context.http.HttpSessionDestructionContext is about).
Finally the helper class that was isolated out to be able to deploy on weblogic and that is doing the vodoo of trying to repair the thread is the following.
Finally, I will probably be opening an issue in : https://issues.jboss.org/projects/WFLY/issues
Thanks for all the help.