https://issues.apache.org/bugzilla/show_bug.cgi?id=57314
Bug ID: 57314 Summary: ServletRequestListener.requestInitialized() and ServletRequestListener.requestDestroyed() called in different threads Product: Tomcat 7 Version: 7.0.57 Hardware: PC OS: Linux Status: NEW Severity: normal Priority: P2 Component: Servlet & JSP API Assignee: dev@tomcat.apache.org Reporter: jozefhartin...@gmail.com TL;DR version: ============== When processing async requests, Tomcat calls ServletRequestListener.requestInitialized() callback from a different thread than the corresponding ServletRequestListener.requestDestroyed() callback. This breaks a lot of frameworks and technologies that depend on ThreadLocals (for example CDI - Weld). All the other Servlet implementations I could get my hands on call these callbacks symmetrically from the same thread. Please fix this. Long version: ============= The Servlet specification is unfortunatelly quite vague when it comes to when and how ServletRequestListeners are called. For a simple synchronous request this is not such a big deal as there are not many options. Both callbacks are called by a thread that processes the request. ServletRequestListener.requestInitialized() at the beginning and ServletRequestListener.requestDestroyed() at the end. So far so good. However, when it comes to asynchronous requests, this gets more complicated. Suppose we have a simple asynchronous servlet that: A1) Does initial processing of the request A2) Goes async (req.startAsync()) A3) Spawns a new thread T that calculates something A4) The servlet exits B1) The spawn thread T calculates the value B2) Once the thread T finishes calculation, it dispatches back to Servlet container for rendering (ctx.dispatch("/asyncFinish?value=calculatedValue")) C1) Servlet container creates response and completes the request A* steps are performed by a thread that initially handles the request. B* steps are performed by a thread spawned by a Servlet, C* steps are performed again by a Servlet container thread. Now the question arises: When and how should ServletRequestListener callbacks be invoked? Common requirements are: 1) Symmetry - each time ServletRequestListener.requestInitialized() is called, there should be a corresponding ServletRequestListener.requestDestroyed() call This I think is clear - if a listener starts something, it should get a chance to stop it. 2) Symmetry with respect to calling thread - each time ServletRequestListener.requestInitialized() is called by thread T, there should be a corresponding ServletRequestListener.requestDestroyed() call by thread T This is an extension of requirement (1) and is needed because frameworks often use ServletRequestListener.requestInitialized() as a hook to set a ThreadLocal for the duration of the request and then unset it in ServletRequestListener.requestDestroyed() Other Servlet containers ======================== As we saw before, the fact that a request is processed in multiple threads may seem in conflict with this second requirement (Symmetry with respect to calling thread - each time). How do other Servlet implementations solve this? They typically do the following: Thread A calls ServletRequestListener.requestInitialized() A1, A2, A3 and A4 are performed Thread A calls ServletRequestListener.requestDestroyed() When the value is calculated by thread B and the request is dispatched to the Servlet container again: Thread C calls ServletRequestListener.requestInitialized() C1 is performed Thread C calls ServletRequestListener.requestDestroyed() This ensures symmetry with respect to a given thread. Tomcat ====== Tomcat simply does: - Thread A calls ServletRequestListener.requestInitialized() - the entire request is processed in threads A, B and C - Thread C calls ServletRequestListener.requestDestroyed() which breaks the second requirement (Symmetry with respect to calling thread). I tested with Tomcat 7 and Tomcat 8 I tested with the following Servlet containers: - Undertow - JBoss Web - Jetty - Grizzly and Tomcat is really the odd one out in not respecting the second requirement. Please fix this so that Tomcat matches the second requirement. -- You are receiving this mail because: You are the assignee for the bug. --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org