Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jetty, myfaces and weld: Expired session cleanup is failing: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped #6506

Closed
38leinaD opened this issue Jul 7, 2021 · 10 comments
Assignees
Labels

Comments

@38leinaD
Copy link

38leinaD commented Jul 7, 2021

Jetty version
We are using Jetty 9.4.42.v20210604 in combination with

  • Weld 3.1.5.Final
  • MyFaces 2.3.8

Java version
openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment 18.9 (build 11.0.8+10)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.8+10, mixed mode)

Question
We are seeing below exception for invalidated sessions and trying to make sense of it:

2021-07-06 22:32:30,016 WARN  [org.eclipse.jetty.server.session] (Session-HouseKeeper-4f4e375c-1): org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
	at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:647)
	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.myfaces.cdi.view.ViewScopeBeanHolder$Proxy$_$$_WeldClientProxy.destroyBeans(Unknown Source)
	at org.apache.myfaces.cdi.impl.CDIManagedBeanHandlerImpl.onSessionDestroyed(CDIManagedBeanHandlerImpl.java:113)
	at org.apache.myfaces.webapp.ManagedBeanDestroyerListener.sessionDestroyed(ManagedBeanDestroyerListener.java:201)
	at org.eclipse.jetty.server.session.SessionHandler$2.run(SessionHandler.java:312)
	at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1520)
	at org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1539)
	at org.eclipse.jetty.server.session.SessionContext.run(SessionContext.java:92)
	at org.eclipse.jetty.server.session.SessionHandler.callSessionDestroyedListeners(SessionHandler.java:316)
	at org.eclipse.jetty.server.session.SessionHandler.invalidate(SessionHandler.java:1216)
	at org.eclipse.jetty.server.session.DefaultSessionIdManager.expireAll(DefaultSessionIdManager.java:436)
	at org.eclipse.jetty.server.session.SessionHandler.scavenge(SessionHandler.java:1267)
	at org.eclipse.jetty.server.session.HouseKeeper.scavenge(HouseKeeper.java:250)
	at org.eclipse.jetty.server.session.HouseKeeper$Runner.run(HouseKeeper.java:62)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)

Essentially, as i understand it, there is a lingering invalid session that is cleand up by jetty. Jetty will inform MyFaces that the session is destroyed. MyFaces tries to do cleanup of the ViewScoped beans that are associated to the session. MyFaces is tracking these ViewScoped beans on a ViewScopeBeanHolder (SessionScoped bean); is trying to get a reference via CDI and CDI tells there is no active scope.
To me, it seems reasonable that there is no active scope on this cleanup thread. Who would have activated the session scope here? it would need to be the session scope that is associated with the session that is cleaned up.

Maybe someone can help shed some light on what is going on and who might be doing something wrong (maybe our integration between the three technologies is incomplete?). Is there some integrationcode between jetty/servlet and CDI not called/invoked/registered that would normally reactivate the SessionScope?

Any help, guess, comments welcome :-)

Thanks in Advance,
Daniel

@joakime
Copy link
Contributor

joakime commented Jul 7, 2021

Looks like the session was destroyed during a HouseKeeper.scavenge() which occurs at a later time.
I thought we set the scope properly for that flow.

Do you have an example project that can cause this?

@janbartel
Copy link
Contributor

@38leinaD can you post a small, simple reproduction?

Jetty uses a background thread to periodically search for HttpSessions that have expired, and then calls into the jetty contexts to invalidate a session with the matching id (can be more than one context due to the "wonders" of cross context dispatch). Before the HttpSessionListener.sessionDestroyed method is called, we anoint the thread with the correct context classloader, so the callback can reference application classes.

From a first reading of the javadocs on the weld code associated with the stacktrace, it looks like there may be an expectation that the HttpSessionContext is always associated with a HttpServletRequest, which is not going to the case when the scavenger thread runs and finds expired HttpSessions. However, as myfaces is also in the mix, it's difficult to isolate the problem. It might be useful if you could create 2 small reproductions: one that uses weld only, and the other that uses weld plus myfaces? Meanwhile, I'll dig further into the weld code to try and understand how the SessionScope stuff is hooked together.

@38leinaD
Copy link
Author

38leinaD commented Jul 8, 2021

I have prepared a "small" reproducer: https://github.com/38leinaD/jetty-issue-reproducer-cleanup-session

After thinking about the problem some more, I am wondering if the rather special integration between jetty and weld could be part of the problem. I tried to preserve the structure in the reproducer. We are actually using WeldSE to boot up a CDI container and a managed bean from here starts Jetty (https://github.com/38leinaD/jetty-issue-reproducer-cleanup-session/blob/master/runtime/src/main/java/Starter.java#L11). I know that Weld will do some additional thingswhen started in EE mode. So, wondering if this could be related; and if so, what piece of integration-code might be missing to run here...
weld-servlet integration is here though: https://github.com/38leinaD/jetty-issue-reproducer-cleanup-session/blob/master/runtime/build.gradle#L54

@janbartel I only prepared a reproducer with myfaces. what do you have in mind regarding a reproducer without myfaces. A plain servelt with an injected @SessionScoped bean? Would that work?

@38leinaD
Copy link
Author

38leinaD commented Jul 9, 2021

I now also created a small example using a servlet and a @SessionScoped bean and no myfaces. But i am not able to reproduce the issue here.
https://github.com/38leinaD/jetty-issue-reproducer-cleanup-session/tree/no-jsf

  • Same steps as before; just open Open http://localhost:8080/hello
  • Close browser...
    No Exception. So, does this indicate that the issue only happens when myfaces is in the mix? Or is my example not valid!?

@janbartel
Copy link
Contributor

@38leinaD thanks for the reproduction test cases, so helpful!

I actually converted them to maven too, to build a standard webapp that I could deploy, just to eliminate any possibility that your embedded code was involved in the problem (it wasn't).

So, from following the stacktraces through the myfaces and cdi code, it appears that myfaces is aware that a HttpSession can be expired outside of any request, see comments like: https://github.com/apache/myfaces/blob/2.3.x/impl/src/main/java/org/apache/myfaces/webapp/ManagedBeanDestroyerListener.java#L190. They take appropriate steps to fabricate a fake FacesContext to deal with this scenario. They are also aware of integration touchpoints with cdi - see comments like https://github.com/apache/myfaces/blob/2.3.x/impl/src/main/java/org/apache/myfaces/cdi/impl/CDIManagedBeanHandlerImpl.java#L100.

The problem appears to be when myfaces calls into cdi that there is no context as far as cdi is concerned - see line org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:647 from the stacktrace.

At this point we are well into myfaces/cdi code territory and jetty appears not to be involved. Just to double-check this assumption, I modified the same webapp deployed to jetty standalone so it was deployable onto tomcat, and I got exactly the same stacktrace.

So, my theory is that we are looking at some kind of mismatch between the jsf and cdi implementations. I recommend you open issues on myfaces and weld and cross reference them both with this issue.

@38leinaD
Copy link
Author

38leinaD commented Jul 12, 2021

Thanks @janbartel !
As suggested, I have created issues with...

@janbartel
Copy link
Contributor

For those following this issue, it looks like this is a known problem for some versions of MyFaces: https://issues.apache.org/jira/browse/MYFACES-4382

@38leinaD
Copy link
Author

Seems to be indeed fixed with myfaces 2.3.9. Will monitor it for a few days in our application and then close this.

@janbartel
Copy link
Contributor

@38leinaD how did you go? Can we close this issue on the jetty side?

@38leinaD
Copy link
Author

Problem was no longer seen with latest myfaces version.
thanks for your support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants