在SpringBoot Controller中异步处理http请求

  |   0 评论   |   0 浏览

背景

在实践中,不同的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();
        }
    });
}

参考

  1. SpringBoot | 第二十章:异步开发之异步请求