首页 > 解决方案 > Restrict number of processed requests per Requestmapping

问题描述

we have a service that has one endpoint which needs to be restricted to process 2 requests at a time. These 2 requests can take a while to be completed.

Currently we use the tomcat properties to do so. The problem we face is now is that - when these 2 threads are used up for that endpoint - our healthcheck does not work anymore.

So we would like to restrict the number of requests for that particular endpoint. We pondered a while about it and one idea was to do so via filter, but that seems very hacky to me...

So I was hoping someone has another idea?

标签: javaspringspring-bootgroovy

解决方案


这是一个如何实现异步 REST 控制器的示例,该控制器将同时处理不超过 2 个并发请求。在处理请求时,此实现不会阻塞任何 Tomcat servlet 线程。

如果在两个正在进行时另一个到达,则调用者将收到 HTTP 429(请求过多)。

此示例立即拒绝无法使用 429 处理的请求。如果您希望将挂起的请求排队,直到 2 个处理线程之一可用,然后替换SynchronousQueueBlockingQueue.

您可能想整理一下这个示例,我特意在此处嵌入了所有用于适合它的类:

@Configuration
@RestController
public class TestRestController {

  static class MyRunnable implements Runnable {

    DeferredResult<ResponseEntity<String>> deferredResult;

    MyRunnable(DeferredResult<ResponseEntity<String>> dr) {
      this.deferredResult = dr;
    }

    @Override
    public void run() {
      // do your work here and adjust the following
      // line to set your own result for the caller...

      this.deferredResult.setResult(ResponseEntity.ok("it worked"));
    }
  }

  @SuppressWarnings("serial")
  @ResponseStatus(HttpStatus.TOO_MANY_REQUESTS)
  static class TooManyRequests extends RuntimeException {
  }

  private final ExecutorService executorService = new ThreadPoolExecutor(2, 2,
      0L, TimeUnit.MILLISECONDS,
      new SynchronousQueue<Runnable>(),
      (runnable, executor) -> {
        ((MyRunnable) runnable).deferredResult.setErrorResult(new TooManyRequests());
      });


  @GetMapping(value = "/blah", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
  public DeferredResult<ResponseEntity<String>> yourRestService() {

    final DeferredResult<ResponseEntity<String>> deferredResult = new DeferredResult<>();
    this.executorService.execute(new MyRunnable(deferredResult));

    return deferredResult;
  }
}

推荐阅读