8

I'm using spring annotations for configuring Controllers(@EnableWebMvc), services(@service and @ComponentScan). In one of my services I have a method annotated with @Async and I also have @EnableAsync added on my config class. When one of MVC controller calls the service method which is annotated with @Async I expect the controller to return immediately without waiting for the service method to complete. By it does not. When I setup the break point in the service method I see that it is in fact running in a seperate thread i.e. the stacktrace does show that it is using SimpleAsyncTaskExecutor as I configured below.

Here is the annotation in my configuration class looks like

@Configuration
@EnableWebMvc
@EnableScheduling
@ComponentScan(basePackages = "com.mypackage")
@EnableAsync
public class WebApplicationConfig extends WebMvcConfigurerAdapter implements AsyncConfigurer {
...
...
@Override
    public Executor getAsyncExecutor() {
        SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor("SimpleExecutor-");
        executor.setConcurrencyLimit(props.getIntegerProperty(SysProps.EMAIL_SENDER_CONCURRENT_THREAD_LIMIT));
        return executor;
    }

And here is my MVC controller method looks like

    @Autowired 
    private EmailService emailService;
    @ResponseStatus(value = HttpStatus.CREATED)
    @RequestMapping(value = "/asset/{assetId}/slideshare/email", method = RequestMethod.POST, produces = JSON_UTF8)
    @ResponseBody
    @ApiResponseObject
    public Link createAndEmailSlideShareLink(@PathVariable final String assetId,
                                             @RequestParam(value = "email") final String email,
                                             @RequestParam(value = "message", required = false) final String message,
                                             final HttpServletRequest request) {
    Link link = linkService.createLink()
    emailService.sendSlideShareAssetEmail(user,link...
    return link;
}

And the service method looks like this

@Async
public void sendSlideShareAssetEmail(User user, String email, String msg, String link, Asset asset) {

Why doesn't the MVC controller does not return immediately?

Srini Kandula
  • 981
  • 2
  • 18
  • 47
  • Post the controller class. What's the return value? – chrylis -cautiouslyoptimistic- May 07 '15 at 22:30
  • @chrylis I updated the post with the code from the controller class. Please check – Srini Kandula May 07 '15 at 22:33
  • You didn't actually post the content of the controller method. – chrylis -cautiouslyoptimistic- May 08 '15 at 00:38
  • The primary thing I was looking for was how you were constructing the return value, which does appear to be independent of the async call. – chrylis -cautiouslyoptimistic- May 08 '15 at 01:33
  • I think i know the problem but before i provide answer can you please show me your code where you extend AbstractAnnotationConfigDispatcherServletInitializer so i can confirm. – Aeseir May 08 '15 at 03:58
  • Sorry for replying late on this. I created a thread pool and switched my code to use it. But to answer your question I configured the dispather server to use AnnotationConfigWebApplicationContext in web.xml. here is the code .... org.springframework.web.servlet.DispatcherServlet contextClass org.springframework.web.context.support.AnnotationConfigWebApplicationContext – Srini Kandula May 19 '15 at 18:43
  • Firstly, is EmailService an interface ? Secondly, the parameters don't match up (user, link...) compared to (user, email...) are you calling a non async method on the service, then calling the async method from that method ? That would not work. – user467257 Jun 09 '15 at 11:36

1 Answers1

0

My guess is that your EmailService bean is being included from two different contexts.

This answer from Ryan Stewart explains the problem/solution in more detail.

Do you have other configurations that are being used? Is there a *-servlet.xml or other servlets defined in your web.xml that might bring your EmailService into the root context?

Do you have a ContextLoaderListener or ServletContextListener defined? Perhaps those are picking up your EmailService in addition to the component scan.

Including your entire source tree as the component-scan path seems suspicious. Try restricting the paths you use in your component scan to exclude your EmailService and see if its still running executing in a SimpleAsyncTaskExecutor. If it is than you know its being brought in from a different context. Once you find the other context you should be able to exclude it there and add it back to your component-scan or EnableAsync in the other context.

Ryan
  • 2,061
  • 17
  • 28
  • Can you provide a short description of the solution? Otherwise this is only a comment and not an answer. – Artjom B. Jul 16 '15 at 19:03