Separate threadpool for url patterns

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Separate threadpool for url patterns

Phil Clay
Hi,

On Tomcat 9.0.12, what is the recommended way of having HTTP requests sent to a certain URL pattern be processed on a separate threadpool from all other requests?


I have found that the HTTP Connectors can only be configured with one executor, therefore all requests always get processed on that single executor.


I tried to implement a Filter that takes advantage of Servlet 3.0 async processing to delegate processing the remaining filterChain to a separate executor, but have found that the filterChain is released after the main thread finishes, and therefore is not usable on the downstream thread pool.

For example:

public class SeparateThreadPoolFilter implements Filter {
    
    private static final Logger logger = LoggerFactory.getLogger(SeparateThreadPoolFilter.class);
    
    private final Executor executor;

    public SeparateThreadPoolFilter(Executor executor) {
        this.executor = executor;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        
        AsyncContext asyncContext = request.startAsync();
        
        executor.execute(() -> {
            try {
                // This chain is no longer usable, because it is released in the main thread after doFilter returns
                chain.doFilter(request, response);
            } catch (IOException | ServletException e) {
                logger.error("Exception occurred while executing HTTP request on separate threadpool" + e);
            } finally {
                asyncContext.complete();
            }
        });
    }

}

I have configured this as the first filter in the chain for the the desired url patterns.  I create and register this filter programmatically, and pass the desired Executor into the constructor.

What I have observed is that after doFilter returns, Tomcat will release the filterChain here...

https://github.com/apache/tomcat/blob/acaeccf3df95b24904c5f0ca9dd0f553d8f43289/java/org/apache/catalina/core/StandardWrapperValve.java#L254

Releasing the filter chain makes it unusable, since it removes all the filters, and the servlet...

https://github.com/apache/tomcat/blob/acaeccf3df95b24904c5f0ca9dd0f553d8f43289/java/org/apache/catalina/core/ApplicationFilterChain.java#L295-L306

Therefore, a NullPointerException occurs within ApplicationFilterChain when it tries to invoke the servlet (which is now null)...

Exception in thread "worker-11" java.lang.NullPointerException
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.example.SeparateThreadPoolFilter.lambda$0(SeparateThreadPoolFilter.java:34)


So my questions are:
1) Is there another way of delegating processing of certain url patterns to a separate threadpool?
2) Is this a bug?  i.e. should filterChains still be usable after doFilter returns if request.startAsync() has been called?

Thank you,

Phil

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: Separate threadpool for url patterns

markt
On 18/10/18 21:39, Phil Clay wrote:

<snip/>

> So my questions are:
> 1) Is there another way of delegating processing of certain url patterns to a separate threadpool?

No. Tomcat does not provide such a feature.

> 2) Is this a bug?  i.e. should filterChains still be usable after doFilter returns if request.startAsync() has been called?

This is not a bug. It is the behaviour required by the Servlet
specification. I recommend you read section 2.3.3.3 of the Servlet spec
for further details.

Mark

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]