Тайм-аут в веб-клиенте Vert.x 3.9 работает не так, как ожидалось

#vert.x #vertx-httpclient

Вопрос:

Мне нужно установить тайм-аут запроса для нисходящего внутреннего вызова. Однако класс WebClient в Vert.x 3.9, похоже, работает не так, как я ожидал. Вот для этого есть некоторый тестовый код:

 package client;

import io.vertx.reactivex.core.AbstractVerticle;
import io.vertx.reactivex.core.Vertx;
import io.vertx.reactivex.ext.web.client.WebClient;

public class Timeout extends AbstractVerticle {
  private static final int port = 8080;
  private static final String host = "localhost";
  private static final int timeoutMilliseconds = 50;

  @Override
  public void start() {
    WebClient client = WebClient.create(vertx);

    for (int i = 0; i < 100; i  ) {
      client.get(port, host, "/").timeout(timeoutMilliseconds).send(
          ar -> {
            if (ar.succeeded()) {
              System.out.println("Success!");
            } else {
              System.out.println("Fail: "   ar.cause().getMessage());
            }
          }); 
    }

    vertx.timerStream(1000).handler(aLong -> { vertx.close(); });
  }

  public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    vertx.deployVerticle(new Timeout());
  }
}
 

Я запускаю следующий сервер Go на том же хосте для тестирования:

 package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", HelloServer)
    http.ListenAndServe(":8080", nil)
}

func HelloServer(w http.ResponseWriter, r *http.Request) {
    fmt.Println("Saying hello!")
    fmt.Fprintf(w, "Hello, %s!", r.URL.Path[1:])
}
 

Вывод для моего тестового сервера показывает, что WebClient открывает 5 одновременных подключений, и каждый запрос останавливается по времени ожидания. Что я здесь делаю не так? Как я должен установить время ожидания соединения для запросов? Вывод от клиента является:

 Fail: The timeout period of 50ms has been exceeded while executing GET / for server localhost:8080
Fail: The timeout period of 50ms has been exceeded while executing GET / for server localhost:8080
Fail: The timeout period of 50ms has been exceeded while executing GET / for server localhost:8080
Fail: The timeout period of 50ms has been exceeded while executing GET / for server localhost:8080
Fail: The timeout period of 50ms has been exceeded while executing GET / for server localhost:8080
Fail: The timeout period of 50ms has been exceeded while executing GET / for server localhost:8080
Fail: The timeout period of 50ms has been exceeded while executing GET / for server localhost:8080
...
 

Я ожидал бы увидеть только «Успех!», так как сервер Go, работающий на том же хосте, должен хорошо реагировать в течение 50 мс.

ИЗМЕНИТЬ: Удалил vertx.close() и уточнил исходный вопрос… На самом деле в моем исходном тестовом коде не было vertx.close (), но я добавил его при редактировании сообщения SO, чтобы людям, которые его запускают, не нужно было нажимать CTRL-C.

Комментарии:

1. какой смысл запускать vertx и убивать его сразу после этого? Вам скорее нужен простой сценарий запуска, чтобы выполнить некоторые запросы веб-клиента…

Ответ №1:

Он зависает, потому что вы блокируете основной поток.

Удалите это:

     try {
      Thread.sleep(1000);
    } catch(InterruptedException ex) {
      Thread.currentThread().interrupt();
    }

    vertx.close();
 

Приложение будет работать до тех пор, пока vert.x жив.

Если вы действительно хотите закрыть vert.x самостоятельно, сделайте это в отдельном потоке.

Или, в качестве альтернативы, сделайте это с помощью самого Vert.x:

 vertx.timerStream(1000).handler(aLong -> {
  vertx.close();
});
 

Ответ №2:

не уверен, что вы пытаетесь там сделать, но есть несколько вещей, которые там неверны:

  1. в AbstractVerticle.start() вас только начинается логика. кроме того, если у вас асинхронная логика, вам необходимо использовать асинхронный интерфейс, например start(Promise<Void> startPromise) , и правильно сообщать о завершении, чтобы Vertx ждал завершения вашей начальной логики.
  2. вы блокируете процесс запуска здесь:
     try {
      Thread.sleep(1000);
    } catch(InterruptedException ex) {
      Thread.currentThread().interrupt();
    }
 

пока это выполняется, ваша вершина на самом деле не запущена, и основной поток vertx заблокирован.

  1. вы никогда не закрываете vertx в начале вертикали! поэтому удалите эту строку vertx.close() и закройте запущенное приложение другим способом.

в общем, проверьте документы, чтобы понять процесс и использование вершин.

Комментарии:

1. Прояснил вопрос. Я вижу, как запускаются подобные запросы, например, здесь, поэтому я не думаю, что тайм-ауты вызваны блокировкой потока: how-to.vertx.io/http-client-howto

2. не знаю, что вы видите в ссылке, но на этой странице нет запроса, отправленного в методе запуска. операция отправки выполняется в периодическом таймере, который запускается вне основного потока.

3. @eof Исключили ли вы возможность того, что запрос просто занял более 50 мс (по какой-либо причине)? Сохраняется ли такое же поведение с такими значениями, как 500 или даже 1000?