I have a REST application implemented with WELD 3.0.5 and RestEasy 3.6.1 running on Tomcat 9.
For the asynchronous requests, Tomcat fires the request destroyed event in a different thread than the one that fired the initialized event.
In this case, WELD, which uses ThreadLocals
, does not deactivate the request context and, as a result, the bean disposal methods are not called.
See: What do WELD-000225, WELD-000335 and WELD-000715 warnings mean?
and Tomcat Bug 57314
My application depends on the container lifecycle events to close resources and clean up, so I need a way to make everything work for async requests as well. The solution I came up with is to add a WebFilter
that invalidates the current request context at the end of the execution chain.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws Exception {
BeanManager beanManager = CDI.current().getBeanManager();
AlterableContext context = (AlterableContext) beanManager.getContext(RequestScoped.class);
try {
chain.doFilter(request, response);
} finally {
if (request.isAsyncStarted()) {
AbstractBoundContext<?> ctxt = (AbstractBoundContext<?>) delegate;
ctxt.invalidate();
ctxt.deactivate();
ctxt.cleanup();
}
}
}
That does a pretty good job discarding the beans and removing some of the thread-local variables. Unfortunately some of the variables remain tied to the pooled thread and Tomcat complains about it:
SEVERE: The web application [cdi-weld] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@3d97cd8b]) and a value of type [org.jboss.weld.module.web.servlet.HttpContextLifecycle.Counter] (value [org.jboss.weld.module.web.servlet.HttpContextLifecycle$Counter@43a15b16]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Nov 02, 2018 10:43:55 AM org.apache.catalina.loader.WebappClassLoaderBase checkThreadLocalMapForLeaks
SEVERE: The web application [cdi-weld] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@21d33dd8]) and a value of type [org.jboss.weld.contexts.AbstractManagedContext.ManagedState] (value [org.jboss.weld.contexts.AbstractManagedContext$ManagedState@2a336421]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
Nov 02, 2018 10:43:55 AM org.apache.catalina.loader.WebappClassLoaderBase checkThreadLocalMapForLeaks
SEVERE: The web application [cdi-weld] created a ThreadLocal with key of type [java.lang.ThreadLocal] (value [java.lang.ThreadLocal@294b0f79]) and a value of type [org.jboss.weld.module.web.servlet.ConversationContextActivator$$Lambda$555/1676983761] (value [org.jboss.weld.module.web.servlet.ConversationContextActivator$$Lambda$555/1676983761@60fb88ad]) but failed to remove it when the web application was stopped. Threads are going to be renewed over time to try and avoid a probable memory leak.
My understanding is that the ThreadLocals get overwritten for each request so that's not exactly a memory leak, but I am still not 100% happy with this solution.
Does anyone know a better way to work around this problem?