I wrote very simple controller which test Servlet 3 features:
@Autowired
ThreadPoolTaskExecutor taskExecutor;
@RequestMapping(value="{name}", method = RequestMethod.GET)
public @ResponseBody DeferredResult<MyResponse> getShopInJSON(@PathVariable String name) {
DeferredResult<MyResponse> df = new DeferredResult<MyResponse>();
taskExecutor.submit(new MyRunnable(df));
return df;
}
In separate Thread I'm doing nothing but 5 second sleep command and after it I return MyResult
POJO to DeferredResult
.
My web.xml file is according to Servlet 3 specifications:
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<display-name>Archetype Created Web Application</display-name>
<servlet>
<async-supported>true</async-supported>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
My Connector tomcat is the following:
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="5"
acceptCount="5"
connectionTimeout="20000"
redirectPort="8443" />
Now this is the interesting part. When running simple program which opens 10 concurrent connection I see that only 5 connections are served first and second 5 connections are served after first set is released (You can see it from time stemps). This is not how Servlet 3.0 should behave
Fri May 31 01:17:57 IDT 2013: Preparing 10 concurrent connections
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 9 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 8 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 4 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 7 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:02 IDT 2013: Output from Server int thread 2 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 1 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 0 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 5 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 6 :{"props1":"param1","props2":"param1"}
Fri May 31 01:18:07 IDT 2013: Output from Server int thread 3 :{"props1":"param1","props2":"param1"}
If change Tomcat Connector to
<Connector connectionTimeout="200000" maxThreads="5" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443"/>
it works like charm. I don't want to do it. According to Tomcat docs I should receive Servlet 3.0 functionality without Http11NioProtocol
connector.
What is wrong?
Introduction In this quick tutorial, we're going to focus on the Servlet 3 support for async requests, and how Spring MVC and Spring Security handle these. The most basic motivation for asynchronicity in web applications is to handle long running requests.
According to the official docs, Spring Security integrates with WebAsyncManager. The first step is to ensure our springSecurityFilterChain is set up for processing asynchronous requests. We can do it either in Java config, by adding following line to our Servlet config class:
... After the HTTP servlet gets the AsyncContext object, any thread that executes acontext.complete () triggers Tomcat to return the response to the client. Surprisingly, I got this behavior by just returning Callable:
3. Spring MVC Async Spring 3.0 introduced the @Async annotation. @Async ‘s goal is to allow the application to run heavy-load jobs on a separate thread. Also, the caller can wait for the result if interested. Hence the return type must not be void, and it be can be any of Future, CompletableFuture, or ListenableFuture.
The problem is due to the maxThreads=5 setting in your Tomcat config.
For the non-NIO case, this setting does not only restrict the maximum number of request processing threads but also restricts the maximum number of connections !
Since you have not specified maxConnections, it is choosing a default value for maxConnections. Here is the excerpt from Tomcat doc on how it chooses the default value for maxConnections:
maxConnections : The maximum number of connections that the server will accept and process at any given time. When this number has been reached, the server will not accept any more connections until the number of connections falls below this value. The operating system may still accept connections based on the acceptCount setting. Default value varies by connector type. For BIO the default is the value of maxThreads unless an Executor is used in which case the default will be the value of maxThreads from the executor. For NIO the default is 10000. For APR/native, the default is 8192.
You can explicitly specify a maxConnections="10" (for example) setting to override this default behavior. You should then see that you can get 10 parallel requests getting processed regardless of the Connector used. I tried this and it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With