在SpringBoot Controller中异步处理http请求
背景
在实践中,不同的url请求的响应速率是不同的。如果一个url响应慢,或者超时时,会影响其它url的请求。
这时,就需要使用异步方式,对于不同的url进行隔离。将不同的url请求放在不同的线程池中执行,这样就不会相互影响了。
之前用Netty实现了线程池的隔离,这次又用SpringBoot实现一次。
初体验
同步调用方式
@RequestMapping("/sync")
public String getRestAsr(AsrParams asrParams, MultipartFile file) {
return metaAsrService.getAsrResult(asrParams, file);
}
改造为异步调用
private ExecutorService executorService;
private final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(1000);
@PostConstruct
private void init() {
this.executorService = new ThreadPoolExecutor(10,10,
60L, TimeUnit.MILLISECONDS,
queue);
}
@RequestMapping("/sync")
public void getRestAsr(AsrParams asrParams, MultipartFile file, HttpServletRequest request, HttpServletResponse response) {
AsyncContext asyncContext = request.startAsync();
asyncContext.addListener(new AsyncListener() {
@Override
public void onComplete(AsyncEvent event) throws IOException {
log.info("on complete, queue size = {}, asrParams = {}", queue.size(), asrParams);
}
@Override
public void onTimeout(AsyncEvent event) throws IOException {
log.info("on timeout, queue size = {}, asrParams = {}", queue.size(), asrParams);
}
@Override
public void onError(AsyncEvent event) throws IOException {
log.info("on error, queue size = {}, asrParams = {}", queue.size(), asrParams);
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
log.info("on start async, queue size = {}, asrParams = {}", queue.size(), asrParams);
}
});
asyncContext.setTimeout(10000);
executorService.submit(() -> {
try {
String result = metaAsrService.getAsrResult(asrParams, file);
asyncContext.getResponse().setContentType("text/plain;charset=UTF-8");
asyncContext.getResponse().getWriter().write(result);
} catch (Exception e) {
log.error("Exception", e);
} finally {
asyncContext.complete();
}
});
}