feat: smart retry max 1 attempt + clear sticky session on failure
- Change antigravitySmartRetryMaxAttempts from 3 to 1 to prevent repeated rate limiting and long waits - Clear sticky session binding (DeleteSessionAccountID) after smart retry exhaustion, so subsequent requests don't hit the same rate-limited account - Add flow diagrams to Forward/ForwardGemini doc comments - Add comprehensive unit tests covering: - Sticky session cleared on retry failure (429, 503, network error) - Sticky session NOT cleared on retry success - Sticky session NOT cleared for non-sticky requests (empty hash) - Sticky session NOT cleared on long delay path (handled by handler) - Nil cache safety (no panic) - MaxAttempts constant verification - End-to-end retryLoop → switchError propagation with session clear
This commit is contained in:
@@ -35,7 +35,7 @@ const (
|
||||
// - 预检查:剩余限流时间 < 此阈值时等待,>= 此阈值时切换账号
|
||||
antigravityRateLimitThreshold = 7 * time.Second
|
||||
antigravitySmartRetryMinWait = 1 * time.Second // 智能重试最小等待时间
|
||||
antigravitySmartRetryMaxAttempts = 3 // 智能重试最大次数
|
||||
antigravitySmartRetryMaxAttempts = 1 // 智能重试最大次数(仅重试 1 次,防止重复限流/长期等待)
|
||||
antigravityDefaultRateLimitDuration = 30 * time.Second // 默认限流时间(无 retryDelay 时使用)
|
||||
|
||||
// Google RPC 状态和类型常量
|
||||
@@ -247,6 +247,11 @@ func (s *AntigravityGatewayService) handleSmartRetry(p antigravityRetryLoopParam
|
||||
}
|
||||
}
|
||||
|
||||
// 清除粘性会话绑定,避免下次请求仍命中限流账号
|
||||
if s.cache != nil && p.sessionHash != "" {
|
||||
_ = s.cache.DeleteSessionAccountID(p.ctx, p.groupID, p.sessionHash)
|
||||
}
|
||||
|
||||
// 返回账号切换信号,让上层切换账号重试
|
||||
return &smartRetryResult{
|
||||
action: smartRetryActionBreakWithResp,
|
||||
@@ -952,6 +957,16 @@ func isModelNotFoundError(statusCode int, body []byte) bool {
|
||||
}
|
||||
|
||||
// Forward 转发 Claude 协议请求(Claude → Gemini 转换)
|
||||
//
|
||||
// 限流处理流程:
|
||||
//
|
||||
// 请求 → antigravityRetryLoop → 预检查(remaining>0? → 切换账号) → 发送上游
|
||||
// ├─ 成功 → 正常返回
|
||||
// └─ 429/503 → handleSmartRetry
|
||||
// ├─ retryDelay >= 7s → 设置模型限流 + 清除粘性绑定 → 切换账号
|
||||
// └─ retryDelay < 7s → 等待后重试 1 次
|
||||
// ├─ 成功 → 正常返回
|
||||
// └─ 失败 → 设置模型限流 + 清除粘性绑定 → 切换账号
|
||||
func (s *AntigravityGatewayService) Forward(ctx context.Context, c *gin.Context, account *Account, body []byte, isStickySession bool) (*ForwardResult, error) {
|
||||
startTime := time.Now()
|
||||
sessionID := getSessionID(c)
|
||||
@@ -1571,6 +1586,16 @@ func stripSignatureSensitiveBlocksFromClaudeRequest(req *antigravity.ClaudeReque
|
||||
}
|
||||
|
||||
// ForwardGemini 转发 Gemini 协议请求
|
||||
//
|
||||
// 限流处理流程:
|
||||
//
|
||||
// 请求 → antigravityRetryLoop → 预检查(remaining>0? → 切换账号) → 发送上游
|
||||
// ├─ 成功 → 正常返回
|
||||
// └─ 429/503 → handleSmartRetry
|
||||
// ├─ retryDelay >= 7s → 设置模型限流 + 清除粘性绑定 → 切换账号
|
||||
// └─ retryDelay < 7s → 等待后重试 1 次
|
||||
// ├─ 成功 → 正常返回
|
||||
// └─ 失败 → 设置模型限流 + 清除粘性绑定 → 切换账号
|
||||
func (s *AntigravityGatewayService) ForwardGemini(ctx context.Context, c *gin.Context, account *Account, originalModel string, action string, stream bool, body []byte, isStickySession bool) (*ForwardResult, error) {
|
||||
startTime := time.Now()
|
||||
sessionID := getSessionID(c)
|
||||
|
||||
Reference in New Issue
Block a user