You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题背景
TCP、HTTP 和 MQTT 网络服务均基于 Vert.x 的异步
listen/绑定接口启动。修复前,三个网络服务提供器在发起异步监听后,没有等待底层 Vert.x Server 的绑定结果,就提前向上游返回了已经创建的
Network实例。这会导致网络服务的响应式生命周期与实际端口监听状态不一致。具体表现包括:
Mono仍可能先成功完成,而实际的端口绑定异常在之后才异步发生。Network实例时,底层 TCP、HTTP 或 MQTT 服务可能尚未真正开始监听。isAlive()主要依赖底层 Server 的端口状态,无法准确区分“底层端口已经产生”与“提供器整体启动已经成功完成”。这些问题会导致调用方错误判断网络服务已经可用,并使端口冲突、部分启动失败和取消启动等场景下的状态与资源管理不可靠。
根因分析
问题的根因是网络提供器没有将 Vert.x 异步监听结果组合到其返回的响应式调用链中。
原有流程大致为:
Network实例。因此,提供器返回的
Mono完成,只能表示“监听操作已经发起”,不能表示“全部监听操作已经成功”。同时,Server 实现中缺少明确的“整体启动完成”状态。仅根据 Server 集合或
actualPort判断存活状态,无法准确表示提供器级别的启动生命周期。修复方案
本次修改统一调整了 TCP、HTTP 和 MQTT 网络服务的启动、失败清理、取消及关闭流程。
1. 等待全部监听操作完成后再返回 Network
三个网络提供器现在会:
Network实例。因此,提供器返回的
Mono成功完成时,可以确定对应的网络服务已经完成实际端口绑定。2. 正确传播端口绑定异常
当任意一个监听操作失败时,例如:
异常会通过提供器返回的
Mono传递给调用方,不再出现“提供器已经成功返回,但端口绑定随后失败”的情况。3. 清理部分启动的 Server
当多个 Server 中的部分实例已经成功绑定、后续实例启动失败时,提供器会触发统一的异步关闭流程,清理已经创建或已经开始监听的所有 Server。
清理完成后,继续向上游传播原始的绑定或监听异常,避免清理操作覆盖真正的启动失败原因。
4. 处理启动阶段的取消
监听调用链增加了取消处理。
当订阅者在启动过程中取消订阅时,会关闭当前创建的网络服务,避免已经绑定的端口继续占用系统资源。
5. 增加明确的启动完成状态
TCP、HTTP 和 MQTT Server 实现均增加了显式启动状态,用于区分:
只有全部监听操作成功之后,才会将该状态设置为已启动。
重新安装 Server 集合、清理 Server 或关闭网络服务时,启动状态会同步重置。
6. 收紧 isAlive() 判定条件
修改后的
isAlive()需要同时满足:这样可以防止底层
actualPort已经为正数、但提供器整体启动尚未完成时,错误地将网络服务报告为存活。7. 统一同步和异步关闭流程
Server 实现新增了用于异常清理的异步关闭能力,并统一处理:
关闭过程中会先提取并清空当前 Server 集合,避免同一批 Server 被重复关闭或继续被
isAlive()使用。涉及范围
本次修改仅涉及以下 6 个网络服务生产代码文件:
TCP
DefaultTcpServerProvider.javaVertxTcpServer.javaHTTP
DefaultHttpServerProvider.javaVertxHttpServer.javaMQTT
DefaultVertxMqttServerProvider.javaVertxMqttServer.java本次修改未涉及:
现有 HTTP Server 构造方法签名保持不变,避免影响已有调用方的二进制兼容性。
修复后的预期行为
修复后,网络服务具有以下行为:
Network时,端口已经真正完成绑定。Mono失败。isAlive()只会在提供器整体启动完成后返回true。shutdown()后,启动状态会重置,监听端口会被释放。验证情况
针对 TCP、HTTP 和 MQTT 三种协议,分别验证了以下场景:
预先占用目标端口后启动网络服务,确认提供器返回的
Mono以绑定异常结束,而不是提前返回成功结果。提供器成功返回后,使用真实连接确认 TCP、HTTP 或 MQTT Server 已经开始监听。
调用关闭方法后,确认:
isAlive()返回false;在底层 Server 已经产生有效
actualPort、但尚未调用整体启动完成逻辑时,确认isAlive()仍然返回false。在网络实例返回附近立即取消订阅,确认不会留下仍然存活、仍然可以连接的监听服务。
以上定向场景已分别对 TCP、HTTP 和 MQTT 执行,并进行了重复验证。
构建验证
Windows 完整编译
执行: