3

This is very similar to the other question here: Spring Boot @Async method in controller is executing synchronously. However my @Service method annotated with @Async is still executing synchronously. I've tried all methods from different forums to no use. Hopefully someone could help me figure out why. A simple spring boot project as below doesn't work.

AsyncConfiguration.java

@Configuration
@EnableAsync
public class AsyncConfiguration(){}

SomeService.java

@Service
public class SomeService() {
  @Async
  public void doSomething() {
    try {
      Thread.sleep(5000L);
    } catch (Exception ignore){}
  }
}

SomeController.java

@Controller
public class SomeController() {

  @Inject SomeService someService;

  @RequestMapping(value="/", method=RequestMethod.POST)
  public String doStuff() {
    someService.doSomething();
    return "mytemplate";
  }
}
Community
  • 1
  • 1
vdkkj
  • 33
  • 1
  • 4
  • you have a `@Configuration` on your `AsyncConfiguration` right? – Stephane Nicoll Sep 14 '15 at 09:47
  • @StéphaneNicoll Yeah I do. I'll edit the question – vdkkj Sep 14 '15 at 09:50
  • Your configuration looks pretty legal, so probably the root of problem somewhere else. Could you share you project on github/bitbucket or create SSCCE (http://sscce.org/)? – Slava Semushin Sep 14 '15 at 09:54
  • can you put logging (with logging of thread name) into SomeService.dosomething() and post log output? – luboskrnac Sep 14 '15 at 09:54
  • If it helps, I'm using the method in `@Service` class to send email using `JavaMailSender` – vdkkj Sep 14 '15 at 09:54
  • I also have the same setup and it just works, but in my case `SomeService` is an interface and I have `SomeServiceImpl` with implementation. So, probably, you could check that you enable something like `spring.aop.proxy-target-class = true`. – Slava Semushin Sep 14 '15 at 09:58
  • I tried it in a fresh project and it seems to be working even without the Service as an interface. There should be some conflicting configuration I guess. The sample working code I used is below after downloading just the web option from [spring-start](http://start.spring.io): [sample](http://pastebin.com/1njmynpE) – vdkkj Sep 14 '15 at 10:37
  • yeah that description of yours does not help because copying that in an actual project should work. That's why sharing a project that exhibits the problem is always better. – Stephane Nicoll Sep 14 '15 at 15:44
  • May be your AsynchConfiguration is not scanned at all by spring. Does it fall in same or sub package of class where you annotated @SpringBootApplication – Phanindra Gopishetty Aug 12 '17 at 06:38

2 Answers2

3

Here is a simple example with @Async. Follow these steps to get @Async to work in your Spring Boot application:

Step 1: Add @EnableAsync annotation and Add TaskExecutor Bean to Application Class.

Example:

@SpringBootApplication
@EnableAsync
public class AsynchronousSpringBootApplication {

    private static final Logger logger = LoggerFactory.getLogger(AsynchronousSpringBootApplication.class);

    @Bean(name="processExecutor")
    public TaskExecutor workExecutor() {
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setThreadNamePrefix("Async-");
        threadPoolTaskExecutor.setCorePoolSize(3);
        threadPoolTaskExecutor.setMaxPoolSize(3);
        threadPoolTaskExecutor.setQueueCapacity(600);
        threadPoolTaskExecutor.afterPropertiesSet();
        logger.info("ThreadPoolTaskExecutor set");
        return threadPoolTaskExecutor;
    }

    public static void main(String[] args) throws Exception {
  SpringApplication.run(AsynchronousSpringBootApplication.class,args);
 }
}

Step 2: Add Method which executes an Asynchronous Process

@Service
public class ProcessServiceImpl implements ProcessService {

    private static final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);

    @Async("processExecutor")
    @Override
    public void process() {
        logger.info("Received request to process in ProcessServiceImpl.process()");
        try {
            Thread.sleep(15 * 1000);
            logger.info("Processing complete");
        }
        catch (InterruptedException ie) {
            logger.error("Error in ProcessServiceImpl.process(): {}", ie.getMessage());
        }
    }
}

Step 3: Add an API in the Controller to execute the asynchronous processing

@Autowired
private ProcessService processService;

@RequestMapping(value = "ping/async", method = RequestMethod.GET)
    public ResponseEntity<Map<String, String>> async() {
        processService.process();
        Map<String, String> response = new HashMap<>();
        response.put("message", "Request is under process");
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

I have also written a blog and a working application on GitHub with these steps. Please check: http://softwaredevelopercentral.blogspot.com/2017/07/asynchronous-processing-async-in-spring.html

  • 1
    That's a good example, but do you know why the @vdkkj's code didn't work? – gkubed Aug 11 '17 at 16:21
  • 1
    If you see Step 1 in my answer, a TaskExecutor Bean with name processExecutor is added to Application Class. This is very important and is used in Step 2 of my answer. I don't see that in @vdkkj's code. – Aj Tech Developer Aug 11 '17 at 18:39
  • 1
    @AjTechDeveloper: That could not be the problem, from the official getting started [blog](https://spring.io/guides/gs/async-method/): "If you do not define an `Executor` bean, Spring creates a `SimpleAsyncTaskExecutor` and uses that. – Jacob van Lingen Dec 12 '19 at 07:36
  • hey, can you add a new url for the post now (2021 the url broke), thanks in advance – qleoz12 Jan 20 '21 at 21:37
  • 1
    Hi @qleoz12, the blog post URL is same as above and it is working: http://softwaredevelopercentral.blogspot.com/2017/07/asynchronous-processing-async-in-spring.html – Aj Tech Developer Mar 19 '21 at 08:01
0

Sorry for my English. The same problem happened to me. The solution was to add

@Autowired
private SomeService someService;

In the Controller class, in this way it allows the class to contain the Beam Configurations associated with "SomeService", thus being able to execute the asynchronous method perfectly.

Here is a project with a functional asynchronous method: https://github.com/JColmenares/async-method-api-rest.git