mirror of
https://gitcode.com/JianFeeeee/webui4frpc.git
synced 2026-10-15 12:14:37 +00:00
上一提交(50c7729)部署后环**仍卡死**,实测 cycle 停在 458198、topology=0、
pending=3。查 .30 日志定位到第二个、也是真正让集群不动的原因:
ring[.30] rejoined cluster via cached peer 192.168.2.60:7500
ring[.30] startup reconcile: reclaimed=0 submitted=3
(此后再无任何 forward cycle / token-send —— 令牌从未转过)
## 根因
retryRejoinCached 在 JoinRing 成功后**直接 return**,把"环会继续转"当作前提。
但 StartRing 只对 leader 生效,而滚动重启恰恰让 leader 自己重入(leader 最后
重启)。此时没有任何节点会转令牌 —— 非 leader 的 StartRing 是 no-op。
结果:leader 重入成功却从不发令牌 → cycle 冻结 → 那三条 pending 转发永远无人
认领 → topology 一直是 0。这与设计文稿 §容错行为不符(环应继续推进)。
## 修法
重入成功后调用 `go ring.StartRing(ctx)`。对非 leader 是 no-op,且内部按
RoundDelay 自节流,多调不会重发,故可无条件调用。
## 测试
TestRejoinThenStartRingCoversTheRejoinPath:用 httptest 起一个假 peer,端到端跑
真正的 retryRejoinCached,断言重入成功后 leader 确实发出了令牌。
★ 这条测试重写过两次才有效:
1. 第一版直接调 `eng.StartRing(...)` —— **假绿**,把修复自己的 helper 当成被测
对象,回退修复行后仍然全绿(已实测确认)。
2. 第二版改走 retryRejoinCached,但传入 httptest 的完整 URL;JoinRing 自己拼
"http://<addr>/api/manager/cluster/join",于是地址变成
`http://http://127.0.0.1:PORT/...` 而永远打不通。改为裸 host:port。
双向验证:移除修复行后如期变红
("after a successful rejoin the leader emitted NO token: the ring is frozen"),
还原后变绿。
go build / go vet / go test ./... 全绿,gofmt 干净。