feat: 模型健康/熔断态 surface 到管理端(T4.F 可观测)
failover/熔断的运行时态原来只在 dispatcher 日志、admin 看不到 —— 本次接到概览可见:
- harness: CircuitBreaker.Snapshot() 只读观测访问器(state + fails,不动状态机)
- llm: Pool.ModelHealth() 上报主备链每模型 {provider,model,role,state,fails};
buildWithFallbacks 把模型名↔breaker 配对(同包直接读 failoverModel.breakers);
newFailoverModel 改返回具体类型以便读 breakers
- dispatcher 心跳 payload 加 models[]
- gateway /admin/overview 独立超时 Ping dispatcher,合并进 models.health
- admin 概览「模型路由」新增「运行时链路态(实时)」:逐模型状态点
(🟢在线/🔴熔断中+失败数/🟡半开探测/单点)
- 单测:Snapshot、Pool.ModelHealth(名字↔态配对/单点/空)
- live:配坏主→提交任务打熔断→概览显示 broken-demo「熔断中·失败3」,备用在线
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -139,3 +139,16 @@ func (c *CircuitBreaker) State() State {
|
||||
defer c.mu.Unlock()
|
||||
return c.state
|
||||
}
|
||||
|
||||
// Snapshot 是熔断器的只读观测快照(供 surface 到管理端)。
|
||||
type Snapshot struct {
|
||||
State State // 当前状态:closed / open / half-open
|
||||
Fails int // 闭合态连续失败计数
|
||||
}
|
||||
|
||||
// Snapshot 返回当前观测快照(不改状态机;管理端展示 breaker 态用)。
|
||||
func (c *CircuitBreaker) Snapshot() Snapshot {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return Snapshot{State: c.state, Fails: c.fails}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,24 @@ func newTestCB(threshold int, cooldown time.Duration, clock *time.Time) *Circuit
|
||||
return c
|
||||
}
|
||||
|
||||
// Snapshot 应如实反映当前状态与连续失败计数(管理端展示用,不改状态机)。
|
||||
func TestCircuitBreaker_Snapshot(t *testing.T) {
|
||||
now := time.Unix(0, 0)
|
||||
c := newTestCB(3, 10*time.Second, &now)
|
||||
if s := c.Snapshot(); s.State != Closed || s.Fails != 0 {
|
||||
t.Fatalf("初始应 closed/0, got %+v", s)
|
||||
}
|
||||
c.Report(false)
|
||||
c.Report(false)
|
||||
if s := c.Snapshot(); s.State != Closed || s.Fails != 2 {
|
||||
t.Fatalf("2 次失败未到阈值应 closed/2, got %+v", s)
|
||||
}
|
||||
c.Report(false) // 第 3 次 → 熔断
|
||||
if s := c.Snapshot(); s.State != Open || s.Fails != 3 {
|
||||
t.Fatalf("阈值后应 open/3, got %+v", s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCircuitBreaker_OpensAfterThreshold(t *testing.T) {
|
||||
now := time.Unix(0, 0)
|
||||
c := newTestCB(3, 10*time.Second, &now)
|
||||
|
||||
Reference in New Issue
Block a user