问题描述
我需要在下游后端调用上设置请求超时。但是,Vert.x 3.9 中的 WebClient 类似乎并没有像我预期的那样工作。这是它的一些测试代码:
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。
解决方法
它挂起是因为你阻塞了主线程。
删除这个:
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();
});
,
不确定您要在那里做什么,但是那里有很多不正确的地方:
-
在
AbstractVerticle.start()
中,您只需要启动逻辑。此外,如果您有异步逻辑,那么您需要使用像start(Promise<Void> startPromise)
这样的异步接口并正确报告完成情况,以便 Vertx 等待您的启动逻辑完成。 -
您在此处阻止了启动过程:
try {
Thread.sleep(1000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
只要这个运行,你的verticle就没有真正启动,vertx的主线程被阻塞了。
- 你永远不会在一个 verticle 开始时关闭 vertx !所以删除这行
vertx.close()
并以另一种方式退出正在运行的应用程序。
一般检查文档以了解顶点的过程和用法。