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

Reply via email to