Olegatorapp
@Olegatorapp
Java/Android dev

Как в Spring разослать асинхронные Http запросы, не блокируя поток?

Всем привет!
Нужна помощь, может кто-то сталкивался с таким... Суть проблемы:
В rest контроллер приходит запрос
метод
@RequestMapping(value = "/ssp/test/{place_hash}", method = RequestMethod.GET)
    @ResponseBody
    public DeferredResult<String> test(
        HttpServletRequest servletRequest, HttpServletResponse servletResponse)
        throws Exception {

        DeferredResult<String> output = new DeferredResult<>();
        this.suspendedRequests.add(output);
        output.onCompletion(() -> suspendedRequests.remove(output));
        new Test(servletRequest, servletResponse, sspHandler).setValue(output);

        return output;
    }


А дальше должна быть следующая последовательность: запрос клиента -> обработка данных запроса -> рассылка на 5 разных сторонних апи и ожидание ответа от них -> сбор данных с этой рассылки, формирование ответа -> возврат ответа клиенту
Проблема именно в том, как собрать обратно эти данные со всех 5 ответов, не задерживая надолго поток? У запросов стоят таймауты по 350 мс, но запрос сам выполняется почти 2 секунды, а это неимоверно долго
Я думал собрать из них ConcurrentLinkedDeque> и колбеками возвращать ответы, но получается, что всё равно поток будет ждать, пока они не закончат отправлять запросы.
  • Вопрос задан
  • 1746 просмотров
Решения вопроса 1
petejones83
@petejones83
Использовать неблокирующий http client? Вроде Apache HttpAsyncClient?
Если нет возможности добавить реактивную библиотеку, то собрать результаты через CompletableFuture и в финальном коллбеке установить значение у DeferredResult.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@kidar2
А может клиент сам сделает эти 5 запросов на сторонние сервисы? Если это веб, то на js задача легко решается Зачем нам промежуточный?
Ответ написан
EugeneP2
@EugeneP2
Java Dev
1) Кэшироапние. Все 5 внешних сервисов возвращают каждый раз уникальный ответ? Или сам сервис каждый раз возвращает уникальный ответ? - Если нет, то ответы нужно кэшировать + ограничивать время жизни кэша.

2) Высокие тайминги внешних сервисов 5 * 350 = ~ 2000 - эти запросы нужно распараллелить. Создаем threadPool на много потоков и добавлять в него задачи Callable и по возвращенным Futures дожидаемся всех результатов и возвращаем их клиенту.

3) увеличить в конфигах максимальное количество потоков самого контейнера (томката/джетти)

4) Запустить сервис на разных машинах/инстансах и настроить лоад балансер, например Ribbon из спрингового стека технологий.

​Правильный совет вам дали sim3x и Довольный Жизнью , реализация через очередь и воркеры с последующим запросом результата клиентом по айди. На такой архитектуре работают много банковских сервисов и выдерживают большие нагрузки.

​Если вам уже так критично количество потоков или вы как то ограничены, то вам стоит обратить внимание на реактивное программирование Spring WebFlux
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы