I joined a new team in my company and I see them using a "ThreadPoolTaskExecutor" extensively. It is basically a Backend REST application for a Front-End, that calls other SOAP APIs and returns the result to the client - simply a passthrough. 99% of the times, each REST endpoint is only calling a single SOAP API and returns the response in json format to the client. However, though it's just a single SOAP call, they use the "ThreadPoolTaskExecutor" and call the .get() blocking method.
ThreadPoolTaskExecutor @Bean on @Configuration class:
@Bean(name=“soapAsyncExecutor")
@Qualifier("soapAsyncExecutor")
public ThreadPoolTaskExecutor getSoapAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
final ThreadFactory customThreadfactory = new ThreadFactoryBuilder()
.setNameFormat(“SoapExecutor-%d")
.setUncaughtExceptionHandler(uncaughtExceptionHandler())
.setDaemon(true)
.build();
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setCorePoolSize(80);
executor.setMaxPoolSize(200);
executor.setQueueCapacity(80);
executor.setKeepAliveSeconds(60);
executor.setAllowCoreThreadTimeOut(true);
executor.setThreadFactory(customThreadfactory);
executor.afterPropertiesSet();
return executor;
}
Code on @Service:
@Async("soapAsyncExecutor")
@Override
public Future<OrderInfo> getOrderInfoAsync(final String orderId) {
return new AsyncResult<OrderInfo>(this.getOrderInfo(orderId);
}
private OrderInfo getOrderInfo(final String orderId) {
// return result from SOAP call which typically take 1 second
}
and then from the @RestController Async method above is called like this:
@GetMapping(value = "/order/{orderId}")
public OrderInfo getOrderInfo(@PathVariable("orderId") final String orderId) {
OrderInfo orderInfo = orderService.getOrderInfoAsync(orderId).get();
return orderInfo;
}
As I understand, each request to a REST endpoint in Spring, spins up a new thread anyway (let's call this the main thread for my lack of a better word). And calling the ".get()" method there is blocking the main thread. My question is, during this blocking period,
- What is the official state of the main thread - "Blocked" or "Waiting"? If Blocked, is there even a slightest benefit of using a "ThreadPoolTaskExecutor" like this for a single job as it makes the main thread block anyway?
- Can this code be tweaked in any way to bring benefit or does it make no sense to use async programming for a single job like this inside a RestController endpoint?