Вот пример того, как реализовать асинхронный контроллер REST, который будет обрабатывать не более 2 одновременных запросов одновременно. Эта реализация не будет блокировать ни один из потоков сервлетов Tomcat во время обработки запросов.
Если во время выполнения двух поступает еще один, вызывающий абонент получит HTTP 429 (слишком много запросов).
В этом примере немедленно отклоняются запросы, которые нельзя обработать с помощью 429. Если вместо этого вы хотите поставить в очередь ожидающие запросы до тех пор, пока не станет доступен один из 2 потоков обработки, замените SynchronousQueue
другой реализацией BlockingQueue
.
Возможно, вы захотите привести этот пример в порядок, я намеренно включил здесь все классы, используемые для его подстановки:
@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;
}
}