6

When invoking a Callable method via ajax running on a Spring Boot application, the embedded tomcat is handling requests asynchronously and perfectly fine:

2017-07-02 09:12:24.283  INFO 3582 --- [nio-8090-exec-3] c.r.web.controllers.MainController       : Ali was stored in redis
2017-07-02 09:12:25.671  INFO 3582 --- [ngAsyncThread-1] c.r.web.controllers.MainController       : Ali is searching for a chat
2017-07-02 09:12:25.820  INFO 3582 --- [ngAsyncThread-1] c.r.web.controllers.MainController       : Ali last activity date was updated in redis
2017-07-02 09:12:26.053  INFO 3582 --- [ngAsyncThread-1] c.r.web.controllers.MainController       : Ali retrieving random conv null
2017-07-02 09:12:26.054  INFO 3582 --- [ngAsyncThread-1] c.r.web.controllers.MainController       : Ali created my own conversation
2017-07-02 09:12:26.211  INFO 3582 --- [ngAsyncThread-1] c.r.web.controllers.MainController       : Ali searching...
2017-07-02 09:12:27.927  INFO 3582 --- [ngAsyncThread-1] c.r.web.controllers.MainController       : Ali searching...
2017-07-02 09:12:29.128  INFO 3582 --- [ngAsyncThread-1] c.r.web.controllers.MainController       : Ali searching...
2017-07-02 09:12:29.305  INFO 3582 --- [nio-8090-exec-2] c.r.web.controllers.MainController       : Zeina was stored in redis
2017-07-02 09:12:29.984  INFO 3582 --- [ngAsyncThread-2] c.r.web.controllers.MainController       : Zeina is searching for a chat
2017-07-02 09:12:30.135  INFO 3582 --- [ngAsyncThread-2] c.r.web.controllers.MainController       : Zeina last activity date was updated in redis
2017-07-02 09:12:30.285  INFO 3582 --- [ngAsyncThread-2] c.r.web.controllers.MainController       : Zeina retrieving random conv Conversation [id=bbb17857-9049-4, person1=Person [id=9a243d57-2f0c-4, name=Ali, age=22, gender=M, ip=0:0:0:0:0:0:0:1, loginDate=Sun Jul 02 09:12:23 EEST 2017, lastActiveDate=Sun Jul 02 09:12:25 EEST 2017], person2=null, creationDate=Sun Jul 02 09:12:26 EEST 2017]
2017-07-02 09:12:30.687  INFO 3582 --- [ngAsyncThread-1] c.r.web.controllers.MainController       : Ali searching...
2017-07-02 09:39:54.420  INFO 3582 --- [ngAsyncThread-3] c.r.web.controllers.MainController       : Zeina is searching for a chat

However, when I deploy the application on an external tomcat server, one call is hanging the server and the next one is only processed after the completion of the first call.

2017-07-02 06:47:57.285  INFO 3324 --- [SpringAsyncThread-4] c.r.web.controllers.MainController       : Zanzoun searching...
2017-07-02 06:47:58.297  INFO 3324 --- [SpringAsyncThread-4] c.r.web.controllers.MainController       : Zanzoun searching...
2017-07-02 06:47:59.309  INFO 3324 --- [SpringAsyncThread-4] c.r.web.controllers.MainController       : Zanzoun searching...
2017-07-02 06:48:00.323  INFO 3324 --- [SpringAsyncThread-4] c.r.web.controllers.MainController       : Zanzoun searching...
2017-07-02 06:48:01.335  INFO 3324 --- [SpringAsyncThread-4] c.r.web.controllers.MainController       : Zanzoun searching...
2017-07-02 06:48:02.347  INFO 3324 --- [SpringAsyncThread-4] c.r.web.controllers.MainController       : Zanzoun searching...
2017-07-02 06:48:03.359  INFO 3324 --- [SpringAsyncThread-4] c.r.web.controllers.MainController       : Zanzoun searching...
2017-07-02 06:48:04.388  INFO 3324 --- [SpringAsyncThread-4] c.r.web.controllers.MainController       : Zanzoun remove dead conversatio
2017-07-02 06:48:04.682  INFO 3324 --- [SpringAsyncThread-5] c.r.web.controllers.MainController       : AJ is searching for a chat
2017-07-02 06:48:04.695  INFO 3324 --- [SpringAsyncThread-5] c.r.web.controllers.MainController       : AJ last activity date was updated in redis
2017-07-02 06:48:04.708  INFO 3324 --- [SpringAsyncThread-5] c.r.web.controllers.MainController       : AJ retrieving random conv Conversation [id=f5fe39ac-91ce-4, person1=Person [id=e25d18f3-9729-4, name=Zanzoun, age=12, gender=F, ip=91.197.46.40, loginDate=Sun Jul 02 06:47:32 UTC 2017, lastActiveDate=Sun Jul 02 06:47:48 UTC 2017], person2=null, creationDate=Sun Jul 02 06:47:48 UTC 2017]
2017-07-02 06:48:50.833  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ is searching for a chat
2017-07-02 06:48:50.845  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ last activity date was updated in redis
2017-07-02 06:48:50.860  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ retrieving random conv null
2017-07-02 06:48:50.860  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ created my own conversation
2017-07-02 06:48:50.872  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ searching...
2017-07-02 06:48:51.884  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ searching...
2017-07-02 06:48:52.896  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ searching...
2017-07-02 06:48:53.908  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ searching...
2017-07-02 06:48:54.921  INFO 3324 --- [SpringAsyncThread-6] c.r.web.controllers.MainController       : AJ searching...

In the above log, the call from Zanzoun and AJ were sent at the same time, however AJ processing didn't start until Zanzoun was over.

Below I list my configurations:

@Configuration
@EnableAsync
public class MvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("main");
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/admin").setViewName("admin");
    }

    @Override
    public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
        configurer.setTaskExecutor(asyncTaskExecutor());
    }

    @Bean
    public AsyncTaskExecutor asyncTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(200);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("SpringAsyncThread-");
        executor.initialize();
        return executor;
    }
}

@SpringBootApplication
@EnableScheduling
@EnableAsync
public class App extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(App.class);
    }
}

Update 1

I applied the answer provided in the comments by @divine , however the problem was not solved:

<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" 
               minProcessors="3"
               maxProcessors="8"
               maxThreads="20"
               connectionTimeout="150000" 
               asyncTimeout="150000" />

Update 2

I have tested locally on my Linux machine using an external Tomcat 8.0.21 and it works perfectly. However, I installed also the same version of Tomcat in Windows (It's actually an AWS instance), and the problem remains the same, so it's an OS/Version issue?

Update 3

Here's the pom file as requested:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.randomni</groupId>
    <artifactId>web</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <!-- Define that this project is a child of the spring-boot-starter-parent 
        project which contains all default maven configuration, this project inherits 
        all these configurations -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.3.RELEASE</version>
    </parent>

    <dependencies>
        <!-- Main Web Dependency, contains MVC and Tomcat -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mobile</artifactId>
        </dependency>
        <!-- Spring MVC with Thymeleaf views -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- Security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- WebJars -->
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>sockjs-client</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>stomp-websocket</artifactId>
            <version>2.3.3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>normalize.css</artifactId>
            <version>5.0.0</version>
        </dependency>
        <!-- For Deployment -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
        <!-- Default Thymeleaf of Spring Boot is version 2, so we had to add these -->
        <thymeleaf.version>3.0.6.RELEASE</thymeleaf.version>
        <thymeleaf-layout-dialect.version>2.2.2</thymeleaf-layout-dialect.version>
    </properties>

</project>
Ali Bassam
  • 9,691
  • 23
  • 67
  • 117
  • 1
    take a look at this answer. https://stackoverflow.com/a/8446513/4525120 – divine Jul 07 '17 at 07:42
  • @divine please check Update #1. – Ali Bassam Jul 07 '17 at 20:05
  • 'When running with embedded tomcat it works fine but when deployed in external tomcat output is not same'- this is the second thread iam noticing this type of issue. Probably because of the tomcat server config not allowing async requests – divine Jul 07 '17 at 20:10
  • Try debugging `o.s.a.i.AsyncExecutionAspectSupport.determineAsyncExecutor()` method to get the idea of what executor you are getting exactly in either case. – jihor Jul 07 '17 at 21:05
  • @jihor the `determineAsyncExecutor()` was never invoked because the interceptor was not of type `InterceptorAndDynamicMethodMatcher`. However I found new things, please check `Update #2`. – Ali Bassam Jul 08 '17 at 04:40
  • @AliBassam why don't you try this? https://stackoverflow.com/a/26213414/4525120 – divine Jul 10 '17 at 08:39
  • @divine doing that will basically kill the purpose of using Spring Boot, gotta have to manually configure everything. – Ali Bassam Jul 11 '17 at 08:04
  • @AliBassam the link i provided is about just manually enabling async support and "not everything". May be your standalone tomcat has set async to off by default. did you try that solution to verify whether it solves your problem? – divine Jul 11 '17 at 08:20

1 Answers1

-1

Have you tried checking the real pool size, for example, through JMX: https://wiki.apache.org/tomcat/FAQ/Monitoring#Thread_Usage?

Also, could you try installing APR Native library to verify the problem is not with auto-selected protocol for incoming traffic: https://tomcat.apache.org/tomcat-8.0-doc/apr.html

The configuration of Windows EC2 instance may also influence the observed behaviour, could you add it to the question, too?

shpikachu
  • 147
  • 1
  • 3
  • 12
  • on the face, i don't really like this answer. Suggestions for possible research opportunities and requests for more information should be a comment instead of an answer. – Jason V Jul 12 '17 at 14:22
  • @Jason neither did I like it as an answer: my reputation yet doesn't allow to leave a comment to the post, was there a different way to communicate with OP? – shpikachu Jul 13 '17 at 09:19
  • unfortunately other than direct messaging no. However, leaving such answers is considered abuse of the answering system as answers need to be kept to concise explanations of the problem. If commenting must wait until you have the requisite 50 rep, so be it. – Jason V Jul 13 '17 at 12:04
  • Well, at least I tried to participate, if that is considered abusive, that doesn't inspire to help people any further, it's just a pity to hear something like that. I tried to cover the directions to investigate for the OP, as obviously there hasn't been any answer besides that. – shpikachu Jul 13 '17 at 12:52
  • 1
    I get what you're saying about trying to participate, and my personal feeling toward the requisite 50 rep for commenting is there shouldn't be a requisite to comment. That being said, rules are rules, and answers are only for clear and concise explanations. – Jason V Jul 13 '17 at 12:56