Correctness39 - SpotBugsExtensionForSpringFrameWork/CS5098 GitHub Wiki

Correctness - Using Try-Catch Block to handle @Async exception with return type void

Description

Since we known that @ExceptionHandler can not handle @Async method, we'd need to use a different way to deal with it. However, we should not use try-catch block for those asynchronous methods with return type void.

Methods annotated by @Async means they are asynchronous methods which will create a new thread to process their logic. In this case, using try-catch block in the @Controller level can not proceed the exception propagated by the @Component class.

@Component TaskFactory:

@Component
public class TaskFactory {

    @Async
    public void asyncTask1(int index) throws InterruptedException {
        int a = 1;
        int b = 0;
        int c;
      
        c = a/b;
        System.out.println("C value is "+c);
    }
  
  	...
}

@Controller:

@RestController
public class TestController {

    @Autowired
    TaskFactory taskFactory;

    @RequestMapping(value = "/welcome", method = RequestMethod.GET)
    public String welcome() throws InterruptedException {
      
        try{
          taskFactory.asyncTask1(i);
        } catch(ArithmeticException e) {
          System.out.println("Exception handled.")
        }
        return "success";
    }
}

In this scenario, exception will not be handled.

Theory

In synchronous cases, a thrown exception is propagated up the call stack until an appropriate handler is found. As shown is Figure 1, the synchronous method with an exception will be handle by the @Controller class.[Exception Handling during Asynchronous Method Invocation - paper]

However, that's not the case in asynchronous method. With @Async annotation, the exception thrown by the method is propagated through the call stack of its thread until the corresponding handler is acquired, as shown in Figure 2.[Unobtrusive Asynchronous Exception Handling with Standard Java Try/Catch Blocks] As the Figure 2 described, the @Async method can not reach the try-catch block inside @Controller because of the disconnection of call stacks (the preceding call stack is not accessible).

Solution

To address this problem, Spring provide AsyncUncaughtExceptionHandler interface to help solve exception handling.

Link

Exception Handling during Asynchronous Method Invocation

Unobtrusive Asynchronous Exception Handling with Standard Java Try/Catch Blocks