Vertx中HttpClient的setTimeout坑

问题描述:

因为特殊原因,导致某一时间段的请求全部超时,当网络恢复正常后,后续的请求还是会继续超时,且服务端也不能再收到任务消息,只能重启客户端服务器。

代码贴示:

private static HttpClientHolder clientHolder = new HttpClientHolder();
public static HttpClient getHttpClient() {
	return clientHolder.get(VertxInstance.getInstance().getVertx(),
			() -> new HttpClientOptions()
					.setMaxPoolSize(ConfigManager.DEFAULT.getInteger(WebGlobals.SECTION_NAME,
					"maxPool", 10));
}

private static void pushMsgToWebServer(JsonObject pushMsgRequest) {
    HttpClient client = getHttpClient();
    
    // Specify both port and host name
    HttpClientRequest clientRequest = client.post(WebGlobals.PORT, WebGlobals.HOST,
            WLGlobals.CALLBACK_URL_PATH, response -> {...});
    clientRequest.exceptionHandler(e -> {
        logger.error(String.format("pushMsgToWebServer response exception:%s", e));
    });
    clientRequest.setTimeout(30000);
    ......
}

原因说明:

首先我们需要理解HttpClient创建连接过程原理:池+队列,setMaxPoolSize是创建一个连接池,还有一个未使用方法setMaxWaitQueueSize用于创建队列大小(默认-1,表示无限大)。
当池被用完之后,新的请求会放入队列里等待。那么如果池的链接一直不归还(closed)那么后面新来的包括已经在等待的则无法被执行。
然后我们再看setTimeout()这个方法源码:

  public synchronized HttpClientRequest setTimeout(long timeoutMs) {
    cancelOutstandingTimeoutTimer();
    currentTimeoutMs = timeoutMs;
    currentTimeoutTimerId = client.getVertx().setTimer(timeoutMs, id -> handleTimeout(timeoutMs));
    return this;
  }

我们当调用这个方法时候,就已经开始进行超时计时(并不是从发出消息那刻算),并且继续深入源码会发现,该方法并无归还链接的操作。
即:一开始池中链接如果超时,并不会被主动释放(服务端调用closed时候,连接会被动释放),则后面依旧继续超时。

解决方案

在创建HttpClientOptions时候设置.setIdleTimeout(),源码中解释如下:
Set the idle timeout, default time unit is seconds. Zero means don't timeout.This determines if a connection will timeout and be closed if no data is received within the timeout.If you want change default time unit, use setIdleTimeoutUnit(TimeUnit)
即超时后会主动关闭连接

引用

https://github.com/eclipse-vertx/vert.x/issues/1842

### Vert.x 中的 WebClient 组件及其用法 #### 创建 WebClient 实例 为了使用 `WebClient` 进行 HTTP 请求,首先需要创建一个 `Vertx` 实例并基于此实例初始化 `WebClient`。 ```java import io.vertx.rxjava.core.Vertx; import io.vertx.rxjava.ext.web.client.WebClient; // 初始化 Vertx 实例 Vertx vertx = Vertx.vertx(); // 基于 Vertx 实例创建 WebClient 客户端 WebClient client = WebClient.create(vertx); ``` #### 发送 GET 请求 通过 `getAbs()` 方法可以发送绝对 URL 的 GET 请求,并利用 RxJava 来处理响应流。这允许开发者采用更简洁的方式管理异步操作的结果[^1]。 ```java client.getAbs("http://example.com") .rxSend() .map(response -> { // 对返回的数据做进一步处理 return response.bodyAsString(); }) .subscribe( result -> System.out.println("接收到的响应:" + result), error -> System.out.println("错误信息:" + error.getMessage()) ); ``` 上述代码片段展示了如何发起一次简单的 GET 请求到指定地址,并对接收的内容进行了字符串化处理后打印出来;同时捕获可能发生的异常情况以便调试或记录日志。 #### 处理 POST 请求和其他方法 除了GET请求外,还可以轻松地构造POST或其他类型的HTTP请求: ```java String jsonBody = "{\"key\":\"value\"}"; client.postAbs("https://api.example.com/endpoint") .putHeader("Content-Type", "application/json") .sendBuffer(Buffer.buffer(jsonBody)) .onSuccess(response -> { String responseBody = response.body().toString(); System.out.println("成功接收数据:" + responseBody); }).onFailure(error -> { System.err.println("发生错误:" + error.getMessage()); }); ``` 这段代码说明了怎样设置自定义头部字段以及传递 JSON 格式的主体内容给服务器端点。它还演示了另一种方式来监听成功的回调事件(`onSuccess`)和失败的情况(`onFailure`)[^1]。 #### 结合其他功能模块 当涉及到复杂的业务逻辑时,可能会与其他组件协作工作,比如数据库访问、消息队列等服务集成。这时就可以借助 Vert.x 提供的各种扩展库完成这些需求[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值