9D5.Async and Errhandle
OriginalPracticeManualAsyncAbout 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 theapplicationTaskExecutor
thread 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
AsyncUncaughtExceptionHandler
only ifvoid
- FailedFuture or non-
void
UncaughtException 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