Как обрабатывать http-запросы к определенному URL в отдельном пуле потоков?
Есть у контроллера два метода с разным URL. Нужно, чтобы запросы к этим URL обрабатывались в разных пулах потоков. Основное, что нужно - чтобы если запросы по первому URL становятся в очередь и не проходят дальше (например, в пуле потоков все потоки заняты), то это не влияло на запросы по второму URL. Как это сделать с помощью Spring?
P.S. Пока я вообще не нашел, как в Spring работают потоки в плане обработки http-запросов (так что, также буду благодарен за любую информацию по этому поводу и полезные ссылки)
P.S.S. Данные методы - это методы проверки liveness и readiness приложения (микросервиса) (понятия берутся из Kubernetes, пробы будут подключаться к этим методам)
P.S.S.S. Приложение на Spring Boot, встроенный сервер приложений не менял
Ответы (1 шт):
2021-03-23 13:17:50.324 INFO 21916 --- [nio-8080-exec-1] com.lampa : start sleep 123 Tue Mar 23 13:17:50 MSK 2021
2021-03-23 13:17:52.200 INFO 21916 --- [nio-8080-exec-2] com.lampa : start sleep 321 Tue Mar 23 13:17:52 MSK 2021
2021-03-23 13:18:00.332 INFO 21916 --- [nio-8080-exec-1] com.lampa : end sleep 123 Tue Mar 23 13:18:00 MSK 2021
2021-03-23 13:18:02.203 INFO 21916 --- [nio-8080-exec-2] com.lampa : end sleep 321 Tue Mar 23 13:18:02 MSK 2021
@Slf4j
@RestController
@RequestMapping("/get")
public class Controller {
@GetMapping("123")
public void get123() throws InterruptedException {
log.info("start sleep 123 {}", new Date());
Thread.sleep(10000);
log.info("end sleep 123 {}", new Date());
}
@GetMapping("321")
public void get321() throws InterruptedException {
log.info("start sleep 321 {}", new Date());
Thread.sleep(10000);
log.info("end sleep 321 {}", new Date());
}
}
Как видно запросы обрабатываются в разных потоках. По умолчанию в spring-boot идет Tomcat 7, потюнить количество потоком можно через server.tomcat.max-threads. Возможно реально кончается пул потоков, посмотрите в сторону DefferedResult как иное решение проблемы:
ExecutorService cachedPool = Executors.newCachedThreadPool();
@GetMapping("111")
public DeferredResult<String> handleReqDefResult() {
DeferredResult<String> output = new DeferredResult<>();
cachedPool.submit(() -> {
log.info("start sleep 111 {}", new Date());
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
log.info("end sleep 111 {}", new Date());
output.setResult("111");
});
return output;
}
Путем изысканий я заменил Executor на свой:
@Configuration
public class ExecutorConfig implements Executor {
ExecutorService fixedThreadPoolMethod1 = Executors.newFixedThreadPool(2);
ExecutorService fixedThreadPoolMethod2 = Executors.newFixedThreadPool(2);
private boolean reverse = false;
@Bean
public TomcatProtocolHandlerCustomizer<?> tomcatProtocolHandlerCustomizer() {
return protocolHandler -> {
protocolHandler.setExecutor(this);
};
}
@Override
public void execute(Runnable command) {
reverse = !reverse;
if(reverse) {
fixedThreadPoolMethod1.execute(command);
}
else {
fixedThreadPoolMethod2.execute(command);
}
}
}
И далее из command можно вытянуть:
SocketProcessorBase<NioChannel> processorBase = (SocketProcessorBase<NioChannel>) command;
из него NioChannel, но вот запрос-то еще не обработан (а он как раз обрабатывается в Executor), поэтому невозможно понять, в каком Executor нужно обработать запрос.