WebClient блокировка вызова – настройка тайм-аута

Вопрос или проблема

Я использую Spring Boot WebClient (SB 3, Java17) в блокирующем режиме

webClient.method(httpMethod)
         .requestUriSpec.uri(url)
         .retrieve()
         .bodyToMono(String.class)
         .block(Duration.ofSeconds(TIMEOUT_IN_SECONDS));

Я читал о настройке различных аспектов, таких как таймауты на ответ/соединение/чтение/запись, на нижнем уровне HTTP клиента. Но это кажется излишним в моем случае, так как все, чего я хочу, это предотвратить блокировку запроса навсегда в случае, если ответа нет после X секунд. Мне не важно, была ли коренная причина в тайм-ауте соединения или тайм-ауте ответа.

Я упускаю или упрощаю что-то?

Одна из причин, по которой я спрашиваю, заключается в том, что время от времени я вижу таймаут на блокировке в журнале, но на стороне, которая получает запрос, я не могу идентифицировать запрос, который долго обрабатывался.

java.lang.IllegalStateException: Таймаут на блокирующем чтении за 3000000000 НАНОСЕКУНД
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:127)
at reactor.core.publisher.Mono.block(Mono.java:1738)

Ответ или решение

Настройка таймаута при использовании WebClient в Spring Boot

Когда вы работаете с WebClient в Spring Boot и необходима блокирующая операция, важным аспектом является правильная настройка таймаута. Давайте разберем, как можно предотвратить бесконечное ожидание ответа при выполнении запроса, особенно в случае, когда неопределенное время простоя может привести к сбоям в приложении.

Ваша текущая реализация

В вашем текущем коде:

webClient.method(httpMethod)
         .requestUriSpec.uri(url)
         .retrieve()
         .bodyToMono(String.class)
         .block(Duration.ofSeconds(TIMEOUT_IN_SECONDS));

вы используете .block(Duration.ofSeconds(TIMEOUT_IN_SECONDS));, чтобы заключить блокирующий вызов в определенные временные рамки. Однако, возникающая ошибка Timeout on blocking read говорит о том, что запрос, который вы сделали, возможно, действительно ожидал ответа долгое время, даже если таймаут уже установлен.

Возможные причины и пути решения

  1. Недостаточная настройка таймаутов: Понимание различных таймаутов, таких как таймаут подключения, таймаут чтения и таймаут записи, является важным. Поскольку вы хотите избежать ожидания ответа на уровне клиента, лучше всего настроить эти параметры. Вы правы, что это может показаться избыточным, но это также поможет лучше контролировать поведение вашего клиента. Например, использование библиотеки HttpClient позволяет явно установить параметры таймаута:
int connectionTimeout = 5000; // 5 секунд
int readTimeout = 5000; // 5 секунд

HttpClient httpClient = HttpClient.create()
    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeout)
    .responseTimeout(Duration.ofMillis(readTimeout));

WebClient webClient = WebClient.builder()
    .clientConnector(new ReactorClientHttpConnector(httpClient))
    .build();
  1. Логгирование запросов: Возможно, то, что вы не видите долгих запросов на стороне сервера, связано с тем, что сервер не получает запросы или они обрабатываются иначе. Настройка логгирования позволит вам детализировать, когда и какие запросы отправляются. Вы можете использовать логгирование на уровне debug, например, добавив конфигурацию логгирования в application.properties:
logging.level.webclient=DEBUG
  1. Отладка сетевых соединений: Если вы подозреваете, что проблема связана со сетевыми задержками или ошибками, добавление инструментов для мониторинга сетевого трафика может помочь выявить, на каком этапе происходит задержка.

  2. Обработка ошибок: Обязательно добавьте обработку ошибок к вашему клиенту, чтобы улавливать и логировать исключения. Например:

webClient.method(httpMethod)
         .requestUriSpec.uri(url)
         .retrieve()
         .bodyToMono(String.class)
         .timeout(Duration.ofSeconds(TIMEOUT_IN_SECONDS)) // используйте метод timeout
         .doOnError(Throwable::printStackTrace) // логирование ошибок
         .block();

Заключение

Ваша интуиция по поводу настройки таймаутов не была ошибочной — более тонкая настройка таймаутов соединения, чтения и записи, а также добавление логгирования могут значительным образом улучшить вывод информации о производительности вашего WebClient. Это не только избавит вас от проблем с блокировками, но и даст вам больше контроля над тем, как обрабатываются ваши HTTP-запросы. Если вы по-прежнему сталкиваетесь с проблемами, возможно, имеет смысл провести более глубокую диагностику сети или провести тестирование на инфраструктурном уровне.

Оцените материал
Добавить комментарий

Капча загружается...