9D5.Async and ErrHandle
Original5/8/24PracticeManualAsyncAbout 1 min
9D5.Async and ErrHandle
In practice, we advocate sync first, and sync as much as possible. The following practices are followed when using async processing.
- Async methods - naming and signing
- Exception handling - exceptions should not be eaten
- Thread pool - thread allocation
9D5.1.Async Annotation
Methods with @Async run in the taskExecutor thread pool, with the default prefix exec-.
- Method name, suffix
Async, e.g.orderAsync. - Return type, use
Future, e.g.CompletableFuture.
In the following code, should NOT use the void method, use Future<Void> and .complete(null) instead. Their main difference is the handling of uncaught exceptions, void eats exceptions and cannot be passed to the caller.
@Async
public void badAsync() {
// exception handled by AsyncConfigurer#getAsyncUncaughtExceptionHandler
}
@Async
public CompletableFuture<Void> goodAsync() {
// exception handled by caller via AOP/ExceptionHandler
return CompletableFuture.completedFuture(null);
}9D5.2.Async webMvc
SpringMvc RequestMapping cannot use @Async, which accomplishes async via the return type.
Future- combines async serviceCallable- combines sync services, using theapplicationTaskExecutorthread pool, with the default prefixapp-exec-DeferredResult- equivalent to passing context, not recommended
In SpringBoot 3.2, thread pools and exceptions are handled as follows, where the
- request and response use the mvc thread pool respectively
- service methods use
app-exec-orexec-depending on how they are called - UncaughtException uses
AsyncUncaughtExceptionHandleronly ifvoid - FailedFuture or non-
voidUncaughtException usesExceptionHandler
The log output, roughly as follows, is detailed in AsyncControllerTest
## `Future` runs in 3 threads
XNIO-1 o.s.web.servlet.DispatcherServlet
XNIO-1 s.w.s.m.m.a.RequestMappingHandlerMapping
XNIO-1 p.f.w.s.a.c.TestAsyncController
exec-2 p.f.w.s.app.service.TestAsyncService
XNIO-1 o.s.w.c.request.async.WebAsyncManager : Async result set
XNIO-1 o.s.web.servlet.DispatcherServlet : Exiting but response remains open
## UncaughtException in exec thread-pool
exec-2 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
## FailedFuture in exec thread-pool
exec-2 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
XNIO-3 o.s.web.servlet.DispatcherServlet : "ASYNC" dispatch
XNIO-3 s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result
## `Callable` runs in 3 threads, with `applicationTaskExecutor`
XNIO-1 o.s.web.servlet.DispatcherServlet
XNIO-1 s.w.s.m.m.a.RequestMappingHandlerMapping
app-exec-2 p.f.w.s.app.service.TestAsyncService
app-exec-2 o.s.w.c.request.async.WebAsyncManager : Async result set
## sync Exception in exec thread-pool
app-exec-2 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
XNIO-3 o.s.web.servlet.DispatcherServlet : "ASYNC" dispatch
XNIO-3 s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result
## `DeferredResult` runs in 3 threads
XNIO-1 o.s.web.servlet.DispatcherServlet
XNIO-1 s.w.s.m.m.a.RequestMappingHandlerMapping
XNIO-1 p.f.w.s.a.c.TestAsyncController
exec-2 p.f.w.s.app.service.TestAsyncService
exec-2 o.s.w.c.request.async.WebAsyncManager : Async result set
XNIO-1 o.s.web.servlet.DispatcherServlet : Exiting but response remains open
## UncaughtException in web thread-pool
XNIO-1 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
## FailedFuture in exec thread-pool
exec-2 o.s.w.c.request.async.WebAsyncManager : Async error, dispatch
XNIO-3 o.s.web.servlet.DispatcherServlet : "ASYNC" dispatch
XNIO-3 s.w.s.m.m.a.RequestMappingHandlerAdapter : Resume with async result