Skip to content

feat(selector): 线路健康检查与自动故障转移 / Line health check & auto failover - #87

Open
suantea wants to merge 1 commit into
PIKACHUIM:mainfrom
suantea:feat/health-failover
Open

suantea wants to merge 1 commit into
PIKACHUIM:mainfrom
suantea:feat/health-failover

Conversation

@suantea

@suantea suantea commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

变更内容 / What

多线路池方案(规划 issue #84)的 M2 里程碑(对齐 #53 节点健康检查与自动故障转移)。为线路引入「持续不可达」健康语义:瞬时失败不切线、持续失败自动剔除候选、恢复后自动召回,并外送通知。

  • selector.ProbeResult 新增 Reachable / ConsecutiveFailures:ProbeAll 刷新连续失败计数后回填,供 API/UI 区分「瞬时失败」与「持续不可达」
  • 健康状态与转换事件:healthy / degraded / unreachable 派生(依据连续失败计数与阈值);仅跨过 unreachable 边界(进入不可达 / 恢复)触发 HealthEvent,healthy↔degraded 抖动不刷屏;SetHealthObserver 注册、锁外派发(防持锁回调死锁)
  • Snapshot().Health:按线路导出健康状态(尚无探测记录的线路不出现)
  • linereg 集成:NewManager 注册观察者 → 写运行日志 + SystemLog(Service=linereg,进入不可达记 warn);SetHealthEventSink 外送(main.go 桥接 callbackMgr.Trigger,事件类型 line_unreachable / line_recovered,callback 任务 UI 创建入口留待后续版本)
  • 语义分离:可用性判定(usable()/lastGood 兜底/失败阈值)保持不变,健康状态只反映失败计数,两者解耦

测试 / Tests

  • selector 3 例:健康字段回填(成功/失败 × Snapshot.Health)、进入不可达与恢复事件序列、阈值>1 时 degraded 静默且仅跨界触发
  • linereg 1 例集成闭环:探测失败 → sink 事件 + SystemLog(warn),恢复同理(info)
  • go vet / go test ./service/selector/ ./service/linereg/ / 子包 go build 全绿

说明

关联

PIKACHUIM

This comment was marked as outdated.

@suantea
suantea force-pushed the feat/health-failover branch 2 times, most recently from 8fe2bc3 to 22541ce Compare September 5, 2026 07:36

@PIKACHUIM PIKACHUIM left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 感谢贡献 @suantea 持续迭代!
🤖 AI 自动审核声明:本评审报告由 AI 自动生成,当前使用 Claude Opus 5 模型进行分析。
⚠️ AI 分析结果仅供参考,可能存在误判或遗漏。
⚠️ 重要提醒:最终是否合并由项目维护者人工判定。

🎯 结论

🔄 Request Changes(出现新冲突,需先 rebase)

🔄 本轮变化

分支 rebase 后追加 2 个公共 commit(ci: fix PR checks + fix(selector): ProbeLines),feature commit(feat(selector): 线路健康检查与自动故障转移)无改动。

🚨 关键问题

[P0] 分支与 main 产生冲突(mergeable: dirty)

compare 显示 ahead 3 / behind 1,冲突文件:

  • .github/workflows/pr-checks.yml
  • backend/main.go
  • backend/service/linereg/linereg.go
  • backend/service/linereg/linereg_test.go
  • backend/service/selector/selector.go
  • backend/service/selector/selector_test.go

原因:公共 ci: fix PR checks commit 与 main 的 CI 改动冲突;main.go/linereg.go 可能与其他堆叠 PR(#81 metrics 挂载、#89 线路入池)产生交叉改动。

建议:git rebase main 解决上述冲突后推送。需特别注意 main.go 与 linereg.go 的冲突取舍(与其他堆叠 PR 的边界)。

✅ 上轮问题回查

  • 上轮 Approve:健康检查 + 故障转移事件闭环优秀,仅 P2(告警/状态变更未同步落库)。
  • feature 内容本轮无变化。

🎯 结论:🔄 Request Changes — 需解决 CI 及 linereg/main.go 冲突后恢复可合并。

@suantea
suantea force-pushed the feat/health-failover branch from d757a2e to 42db3e2 Compare September 10, 2026 14:15

@pikachuren pikachuren left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 感谢 @suantea 提交!
🤖 AI 自动审核声明:本评审报告由 AI 自动生成,当前使用 DeepSeek-V4.1-Flash 模型进行分析。
⚠️ AI 分析结果仅供参考,可能存在误判或遗漏。如您发现任何问题或有不同意见,欢迎随时提出讨论和纠正。
⚠️ 重要提醒:即使 AI 评审认为代码质量良好且建议合并,最终是否合并仍需由项目维护者进行人工判定。项目维护者会综合考虑代码质量、项目规划、技术方向、团队资源等多方面因素做出是否合并的决策。

增量口径说明(重要):上轮评审锚点 d757a2e535 已不可按 sha 获取(git fetch origin d757a2e535 返回 couldn't find remote ref,该 commit 已被 rebase 掉、在远端不可达),因此改用内容比对:经 GitHub API 取旧分支的 feature commit 7d1b23464d 及其父 b688e5fc37 的原始文件,与当前 HEAD 42db3e2 的文件逐一 diff。比对结果:除 main 后来并入的 ProbeLines 取消修复(c33387d / #88,属上游代码)外,本 PR 自身 5 个文件内容零变化。
行号为本轮 HEAD 文件的真实行号。

🔄 增量评审:d757a2e535 → 42db3e2

本轮新增 1 个 commits / 变更 5 个文件:backend/main.go、backend/service/linereg/linereg.go、backend/service/linereg/linereg_test.go、backend/service/selector/selector.go、backend/service/selector/selector_test.go

(实为「rebase 到最新 main + squash 为单一 commit」:原分支上的 2 个公共 commit ci: fix PR checks、fix(selector): ProbeLines 已随上游并入而消失,健康检查/故障转移功能代码逐字未改。)

新增改动的问题(按 P0/P1/P2 分级):

  • ⚠️ [P2] PR 描述已过时 — 描述中「本地既有 TestProbeLinesCancellation 在纯上游 main 上同样失败……建议另立小 PR 修复」这一备注在本轮已不适用:main 已于 c33387d(#88)合入同一份取消修复,本分支 selector.go:427-436 与 main 逐字一致,分歧点消失。建议更新描述。
  • (说明)本轮不涉及新的代码逻辑,故无 P0/P1 级新增问题。

旧问题解决情况(逐条回查上轮两份评审):

  • ✅ [P0] 分支与 main 冲突(mergeable: dirty,冲突文件 .github/workflows/pr-checks.yml、backend/main.go、backend/service/linereg/linereg.go、linereg_test.go、backend/service/selector/selector.go、selector_test.go 共 6 个)— 已解决。本轮分支为 dc2877b(origin/main) 之上的单一 commit,git merge-base --is-ancestor origin/main refs/remotes/pr/87 成立(线性、无冲突源);丢弃的公共 commit 中,pr-checks.yml 的 artifact 逻辑 main 已自带(pr-checks.yml:48-72),ProbeLines 修复 main 已由 #88 并入。CI 两个 check 均为 success(Backend build+test / Frontend typecheck+build)。
  • ❌ [P2] backend/service/linereg/linereg.go:383(落库语句在 :393)handleHealthEvent 在探测循环 goroutine 内同步写库 — 未处理。本轮内容与上轮逐字一致,仍是回调内联 m.db.Create(&model.SystemLog{...})(m.selector.SetHealthObserver → handleHealthEvent 的调用链见 linereg.go:119-120),健康事件本身低频、影响有限,仍建议后续改为「channel 缓冲 + 独立 writer」避免 SQLite 锁竞争时阻塞探测循环。
  • N/A 上轮「待处理清单」仅上述 1 条 P2,无其它遗留项。

🎯 结论:✅ Approve — 上轮唯一的 P0(与 main 冲突)已随 rebase+squash 彻底解决、线性可合并且 CI 全绿,健康事件闭环实现与上次已认可的版本逐字一致,仅余 1 条 P2 落库异步化建议与 1 条描述更新提醒。

@PIKACHUIM

Copy link
Copy Markdown
Owner

还是有冲突,暂时无法合并
建议每个PR都基于main重新创建,并且PR之间的修改不要重叠

1 similar comment
@PIKACHUIM

Copy link
Copy Markdown
Owner

还是有冲突,暂时无法合并
建议每个PR都基于main重新创建,并且PR之间的修改不要重叠

@suantea
suantea force-pushed the feat/health-failover branch from 42db3e2 to f6962bc Compare September 20, 2026 13:55
@suantea

suantea commented Sep 20, 2026

Copy link
Copy Markdown
Collaborator Author

已 rebase 到最新 main 并解决了与 #85(加权选线)在 selector.go / selector_test.go 的冲突,现在 mergeable 了,麻烦您再看一下。

关于分支重叠的问题,我这边会按您的建议统一处理:

  1. 已 rebase:feat(selector): 线路健康检查与自动故障转移 / Line health check & auto failover #87(本 PR)、feat(frpmaster): frpc 多节点 Master 控制面基础 / frpc multi-node Master control plane #86、feat(frpmaster): 远程线路入池与节点日志聚合 / Remote lines pool & node log aggregation #89、feat(rbac): add three-role layer on top of admin-only (PR #1 of #65) #90、feat(security): AES-256-GCM encryption for sensitive config (PR-5 of #64) #94、feat(mtls): add CA signing module for node certificate management (PR-1 of #61) #95 — 全部基于最新 main 重建,剔除与 main 及其他 PR 重复的提交;
  2. 有一组健康度/保留策略 PR(feat(retention): scheduled data retention cleanup to prevent unbounded DB growth #114→perf(ui): on-demand echarts imports + vendor chunk splitting, main bundle ~1MB → 304kB #121)是有意按依赖关系分层提交的(如 feat(ui): topbar health badge consuming /system/health endpoint #120 的 UI 依赖 feat(health): /system/health self-check endpoint with engine heartbeats #117 的 /system/health 端点),会从最底层的 feat(retention): scheduled data retention cleanup to prevent unbounded DB growth #114 开始按顺序依次合并,合并一层后上面各层会自动消除重叠,我会保持每层都基于最新 main 可独立编译测试;
  3. 每个 PR 保持单一主题,review 时如果某个 PR 仍含无关改动,我直接拆出单独 PR。

@pikachuren pikachuren left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 感谢 @suantea 提交!
🤖 AI 自动审核声明:本评审报告由 AI 自动生成,当前使用 Claude Opus 5 模型进行分析。
⚠️ AI 分析结果仅供参考,可能存在误判或遗漏。如您发现任何问题或有不同意见,欢迎随时提出讨论和纠正。
⚠️ 重要提醒:即使 AI 评审认为代码质量良好且建议合并,最终是否合并仍需由项目维护者进行人工判定。项目维护者会综合考虑代码质量、项目规划、技术方向、团队资源等多方面因素做出是否合并的决策。

🔄 增量评审:v1 → v2

本轮新增 1 个 commits,变更 5 个文件:backend/main.go、backend/service/linereg/linereg.go、backend/service/linereg/linereg_test.go、backend/service/selector/selector.go、backend/service/selector/selector_test.go

新增改动的问题(按 P0/P1/P2 分级):

  • ⚠️ [P2] PR 描述已过时 — 描述中「本地既有 TestProbeLinesCancellation 在纯上游 main 上同样失败……建议另立小 PR 修复」这一备注已不适用:main 已于 c33387d(#88)合入同一份取消修复,本分支代码与 main 逐字一致,分歧点消失。建议更新 PR 描述以反映当前状态。
  • 无新增代码逻辑问题。

旧问题解决情况:

  • ✅ [P0] 分支与 main 冲突(mergeable: dirty,6 个文件冲突) — 已完全解决。本轮为单一 commit(线性、无冲突源),两个 CI check 均 success(Backend build+test / Frontend typecheck+build)。
  • ❌ [P2] handleHealthEvent 在探测循环 goroutine 内同步写库(backend/service/linereg/linereg.go:119-120) — 未处理。本轮内容与上轮逐字一致,仍是回调内 m.db.Create(&model.SystemLog{...}),健康事件本身低频、影响有限,建议后续改为「channel 缓冲 + 独立 writer」避免 SQLite 锁竞争时阻塞探测循环。

🎯 结论:✅ Approve — 上轮唯一的 P0(与 main 冲突)已随 rebase+squash 彻底解决,线性可合并且 CI 全绿,健康事件闭环实现与上次已认可版本逐字一致。仅建议更新 PR 描述并在后续版本跟进异步写库优化。

- ProbeResult 新增 Reachable / ConsecutiveFailures:由 ProbeAll 在刷新
  连续失败计数后回填,供 API/UI 区分「瞬时失败」与「持续不可达」
- 健康状态派生(healthy/degraded/unreachable)+ 转换事件:仅跨过
  unreachable 边界(进入不可达 / 恢复)触发 HealthEvent,healthy↔degraded
  的瞬时抖动不刷屏;观察者经 SetHealthObserver 注册,锁外派发防死锁
- Snapshot().Health:按线路导出健康状态(无探测记录的线路不出现)
- linereg 集成:NewManager 注册健康观察者 → handleHealthEvent 写运行日志 +
  SystemLog(Service=linereg,进入不可达记 warn);SetHealthEventSink 支持
  外送(main.go 桥接 callbackMgr.Trigger,trigger_type: line_unreachable /
  line_recovered,UI 创建入口后续版本提供)
- 现有可用性语义不变:usable()/lastGood 兜底/失败阈值照旧,健康状态只
  反映失败计数,两者分离
- 测试:selector 3 例(健康字段回填 / 进入与恢复事件 / 阈值>1 时 degraded
  静默与跨界触发);linereg 1 例集成闭环(探测失败→SystemLog+sink,恢复同理)

注:本地 go 1.27 下既有 TestProbeLinesCancellation 在纯上游 main 同样失败
(select 双就绪随机竞争,CI go 1.25 全绿),与本次改动无关,另立修复。

Co-Authored-By: AtomCode (deepseek-v4-flash) <noreply@atomgit.com>
@suantea
suantea force-pushed the feat/health-failover branch from f6962bc to 47dd524 Compare September 23, 2026 09:01

@pikachuren pikachuren left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🙏 感谢 @suantea 提交!
🤖 AI 自动审核声明:本评审报告由 AI 自动生成。
⚠️ AI 分析结果仅供参考;最终合并决策由项目维护者判定。

🎯 结论

✅ Approve(建议补上恢复阈值后合并)

📖 概要

线路健康检查与自动故障转移 · M2 里程碑 · 与 #86/#89 无代码依赖,可独立合并
核心改动:在 selector/linereg 新增健康状态语义层,仅在 unreachable 边界触发 HealthEvent,与 usable() 判定解耦

🧭 整体方案

纯粹横向能力增强——只在 selector 内新增健康状态派生 + 边界事件分发,不修改任何现有业务路径,分层干净。

📊 变更统计

5 个文件(+308 / -5 行) | 功能 ⭐⭐⭐⭐ | 最小改动 ⭐⭐⭐⭐⭐ | 前向兼容 ⭐⭐⭐⭐⭐ | 方案设计 ⭐⭐⭐⭐

🚨 关键问题

P1(建议修复):

  • 💡 backend/service/selector/selector.go stateOf 函数:进入不可达需连续失败达 failureThreshold(默认2),但恢复只需 1 次成功,不对称——线路在临界状态反复成功/失败时,健康事件会以"每 3 轮触发一次"的频率持续产生,导致通知/回调抖动。仓库中 MonitorProbe 模型已有 FailThreshold/RecoverThreshold 双阈值先例,建议同步引入 recoverThreshold,或要求 N 次连续成功才回到 healthy。

P2(可选):

  • 💡 selector_test.go 缺少"持续交替成功/失败"的抖动频率模拟测试,建议补充以量化事件产生速率。

✅ 待处理清单

  • [P1] 引入 recoverThreshold 使恢复阈值与失败阈值对称

🎯 结论:✅ Approve — 功能独立、测试充分、无破坏性变更,P1 建议补充但不阻塞合并

This branch has not been deployed

No deployments
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.

3 participants