Как обрабатывать http-запросы к определенному URL в отдельном пуле потоков?

Есть у контроллера два метода с разным URL. Нужно, чтобы запросы к этим URL обрабатывались в разных пулах потоков. Основное, что нужно - чтобы если запросы по первому URL становятся в очередь и не проходят дальше (например, в пуле потоков все потоки заняты), то это не влияло на запросы по второму URL. Как это сделать с помощью Spring?

P.S. Пока я вообще не нашел, как в Spring работают потоки в плане обработки http-запросов (так что, также буду благодарен за любую информацию по этому поводу и полезные ссылки)

P.S.S. Данные методы - это методы проверки liveness и readiness приложения (микросервиса) (понятия берутся из Kubernetes, пробы будут подключаться к этим методам)

P.S.S.S. Приложение на Spring Boot, встроенный сервер приложений не менял


Ответы (1 шт):

Автор решения: lampa
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 нужно обработать запрос.

→ Ссылка