Skip to content

fix: 被动端监听韧性加固(#47)——重试延迟出锁 + SO_REUSEADDR - #48

Merged
CSJ608 merged 2 commits into
mainfrom
fix-reconnect-listener-wedge
Aug 29, 2026
Merged

CSJ608 merged 2 commits into
mainfrom
fix-reconnect-listener-wedge

Conversation

@CSJ608

@CSJ608 CSJ608 commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Closes #47

排查结论(先说重要的):原始"楔死"无法复现

按 issue 里的诊断步骤做了三组复现尝试,全部通过:

  1. 顺序复现:8 轮"对端接入 → 服务端显式 Reconnect()(服务端主动关闭)→ 端口须在 10s 内可重新接受"——全程秒级可用,零 accept 失败日志。Windows 实测允许重绑覆盖服务端主动关闭留下的 TIME_WAIT,原 TIME_WAIT 假设不成立;
  2. 并发复现:每轮同时触发杀对端(自动重连)与用户 Reconnect()(bug: 用户显式 Reconnect() 与自动重连竞速可长期楔死被动端监听(重绑失败 + 接受循环持有锁重试) #47 的竞速形态)——3× 全过;
  3. 混沌回归:把用户 Reconnect() 动作加回混沌套件,20s/30s 多轮全绿。

回溯判定:此前观察到的 60 秒+拒绝,是当时混沌测试自身三个缺陷的组合(双重连接泄漏占住单客户端、收尾未释放存活对端、变量遮蔽导致的静默编译失败使我们一度在跑旧二进制)——这些已在 PR #46 排除。库的接受机制(含用户重连与自动重连竞速)经证实收敛正确。

仍然落地的两个防御性修复(排查中识别的真实弱点)

弱点 修复
接受循环的整个重试 while 持有 _acceptLock——若将来因任何原因(外部端口占用、防火墙拦截…)持续绑定/接受失败,重试延迟期间会堵死其它接受循环,故障期被放大为全停 AcceptAsync 重构为逐次尝试持锁,重试延迟在锁外等待
监听 socket 未设 SO_REUSEADDR——Windows 实测宽松,但 Linux 上无此选项时重绑遇 TIME_WAIT 会 EADDRINUSE(跨平台部署的经典坑),当前 ubuntu CI 未踩中属时序运气 InitServer 设置 ReuseAddress,跨平台行为一致

测试

  • 新增确定性回归 RapidServerInitiatedReconnects_PortStaysAcceptable(8 轮服务端主动重连 + 并发竞速触发,10s 上限);
  • 混沌套件恢复用户重连动作,随 soak 常驻验证;
  • 全量 84×3 = 252 绿。

备注

issue 里的"阶段二(单一飞行重连 generation)"与"阶段三(状态过渡原子化)"在复现不能成立的前提下收益只剩理论值,暂不实施;若未来真实环境再次出现楔死,按本 PR 已加固的两处排查(现在 accept 失败有 Warning 日志且不持锁)。

Marci added 2 commits August 29, 2026 09:28
排查结论:原始"用户 Reconnect() 竞速楔死监听"无法复现——顺序复现(8 轮
服务端主动重连,全部秒级可用)与并发复现(杀对端自动重连 + 用户 Reconnect
竞速)均 3× 通过;混沌套件恢复该动作后 20s/30s 多轮全绿。此前观察到的楔死
系当时混沌测试自身的缺陷组合(双重连接泄漏 + 收尾未释放对端 + 变量遮蔽致
静默编译失败),已在 PR #46 排除。

仍修复排查中识别的两个真实弱点(防御性):
- AcceptAsync 改为逐次尝试持锁、重试延迟锁外等待——旧实现整个重试循环
  持有 _acceptLock,绑定/接受持续失败期间会堵死其它接受循环,故障期被放大
- 监听 socket 设置 SO_REUSEADDR——服务端主动关闭后立即重绑不受 2MSL/
  TIME_WAIT 限制;Windows 实测宽松,Linux 无此选项会遇 EADDRINUSE,
  一并设置保持跨平台一致

新增确定性回归测试 RapidServerInitiatedReconnects_PortStaysAcceptable;
混沌套件恢复用户重连动作并常驻验证。
CI(ubuntu) 暴露:server.Start() fire-and-forget,首次连接若无重试会撞上
监听器尚未 bind 的启动窗口被拒(Windows 时序快未显形)。测试内全部
连接改带 10s 预算的重试。
@CSJ608
CSJ608 merged commit feb99a3 into main Aug 29, 2026
4 checks passed
@CSJ608
CSJ608 deleted the fix-reconnect-listener-wedge branch August 29, 2026 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: 用户显式 Reconnect() 与自动重连竞速可长期楔死被动端监听(重绑失败 + 接受循环持有锁重试)

1 participant