M5: 渠道体系(负载均衡+并发控制+健康检查+故障转移)

- channel.Candidates 按模型绑定取候选 + Pick 加权随机负载均衡
- TryAcquire 每渠道并发信号量, 满载溢出到其他候选
- HealthMonitor 后台定时探测, 连续失败进 cooldown, 恢复放回(可配 interval/threshold)
- doProxy 遍历候选故障转移: 网络错误/429/5xx/超时且未写出响应头时安全重试;
  400 等业务错误透传, 流式写出首字节后放弃重试
- 单测覆盖候选过滤/加权/并发/健康状态机
- E2E: 杀上游自动切换、cooldown、恢复、并发溢出 10/10

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sakurasan
2026-08-15 15:57:48 +08:00
co-authored by Claude
parent ec4de8d913
commit 0637ce0a51
11 changed files with 454 additions and 97 deletions
+3 -8
View File
@@ -123,14 +123,9 @@ func (g *Gateway) models(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"object": "list", "data": data})
}
// selectChannel 选渠道:优先按模型绑定解析,退化为全局选渠道。
func (g *Gateway) selectChannel(c *gin.Context, model string) (*store.Channel, error) {
if model != "" {
if ch, _, err := g.ch.ResolveModel(model); err == nil {
return ch, nil
}
}
return g.ch.Select()
// candidateChannels 返回可用渠道候选(按模型绑定优先,退化全局)。
func (g *Gateway) candidateChannels(model string) []*store.Channel {
return g.ch.Candidates(model)
}
// resolveUser 取当前用户(含余额)。