feat(antigravity): 动态 URL 排序,最近成功的优先使用
- URLAvailability 新增 lastSuccess 字段追踪最近成功的 URL - GetAvailableURLs 返回列表时优先放置 lastSuccess - 所有 Antigravity API 调用成功后调用 MarkSuccess 更新优先级
This commit is contained in:
@@ -358,6 +358,8 @@ func (c *Client) LoadCodeAssist(ctx context.Context, accessToken string) (*LoadC
|
|||||||
var rawResp map[string]any
|
var rawResp map[string]any
|
||||||
_ = json.Unmarshal(respBodyBytes, &rawResp)
|
_ = json.Unmarshal(respBodyBytes, &rawResp)
|
||||||
|
|
||||||
|
// 标记成功的 URL,下次优先使用
|
||||||
|
DefaultURLAvailability.MarkSuccess(baseURL)
|
||||||
return &loadResp, rawResp, nil
|
return &loadResp, rawResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,6 +451,8 @@ func (c *Client) FetchAvailableModels(ctx context.Context, accessToken, projectI
|
|||||||
var rawResp map[string]any
|
var rawResp map[string]any
|
||||||
_ = json.Unmarshal(respBodyBytes, &rawResp)
|
_ = json.Unmarshal(respBodyBytes, &rawResp)
|
||||||
|
|
||||||
|
// 标记成功的 URL,下次优先使用
|
||||||
|
DefaultURLAvailability.MarkSuccess(baseURL)
|
||||||
return &modelsResp, rawResp, nil
|
return &modelsResp, rawResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,11 +51,12 @@ var BaseURLs = []string{
|
|||||||
// BaseURL 默认 URL(保持向后兼容)
|
// BaseURL 默认 URL(保持向后兼容)
|
||||||
var BaseURL = BaseURLs[0]
|
var BaseURL = BaseURLs[0]
|
||||||
|
|
||||||
// URLAvailability 管理 URL 可用性状态(带 TTL 自动恢复)
|
// URLAvailability 管理 URL 可用性状态(带 TTL 自动恢复和动态优先级)
|
||||||
type URLAvailability struct {
|
type URLAvailability struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
unavailable map[string]time.Time // URL -> 恢复时间
|
unavailable map[string]time.Time // URL -> 恢复时间
|
||||||
ttl time.Duration
|
ttl time.Duration
|
||||||
|
lastSuccess string // 最近成功请求的 URL,优先使用
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultURLAvailability 全局 URL 可用性管理器
|
// DefaultURLAvailability 全局 URL 可用性管理器
|
||||||
@@ -76,6 +77,15 @@ func (u *URLAvailability) MarkUnavailable(url string) {
|
|||||||
u.unavailable[url] = time.Now().Add(u.ttl)
|
u.unavailable[url] = time.Now().Add(u.ttl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkSuccess 标记 URL 请求成功,将其设为优先使用
|
||||||
|
func (u *URLAvailability) MarkSuccess(url string) {
|
||||||
|
u.mu.Lock()
|
||||||
|
defer u.mu.Unlock()
|
||||||
|
u.lastSuccess = url
|
||||||
|
// 成功后清除该 URL 的不可用标记
|
||||||
|
delete(u.unavailable, url)
|
||||||
|
}
|
||||||
|
|
||||||
// IsAvailable 检查 URL 是否可用
|
// IsAvailable 检查 URL 是否可用
|
||||||
func (u *URLAvailability) IsAvailable(url string) bool {
|
func (u *URLAvailability) IsAvailable(url string) bool {
|
||||||
u.mu.RLock()
|
u.mu.RLock()
|
||||||
@@ -87,14 +97,29 @@ func (u *URLAvailability) IsAvailable(url string) bool {
|
|||||||
return time.Now().After(expiry)
|
return time.Now().After(expiry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAvailableURLs 返回可用的 URL 列表(保持优先级顺序)
|
// GetAvailableURLs 返回可用的 URL 列表
|
||||||
|
// 最近成功的 URL 优先,其他按默认顺序
|
||||||
func (u *URLAvailability) GetAvailableURLs() []string {
|
func (u *URLAvailability) GetAvailableURLs() []string {
|
||||||
u.mu.RLock()
|
u.mu.RLock()
|
||||||
defer u.mu.RUnlock()
|
defer u.mu.RUnlock()
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
result := make([]string, 0, len(BaseURLs))
|
result := make([]string, 0, len(BaseURLs))
|
||||||
|
|
||||||
|
// 如果有最近成功的 URL 且可用,放在最前面
|
||||||
|
if u.lastSuccess != "" {
|
||||||
|
expiry, exists := u.unavailable[u.lastSuccess]
|
||||||
|
if !exists || now.After(expiry) {
|
||||||
|
result = append(result, u.lastSuccess)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加其他可用的 URL(按默认顺序)
|
||||||
for _, url := range BaseURLs {
|
for _, url := range BaseURLs {
|
||||||
|
// 跳过已添加的 lastSuccess
|
||||||
|
if url == u.lastSuccess {
|
||||||
|
continue
|
||||||
|
}
|
||||||
expiry, exists := u.unavailable[url]
|
expiry, exists := u.unavailable[url]
|
||||||
if !exists || now.After(expiry) {
|
if !exists || now.After(expiry) {
|
||||||
result = append(result, url)
|
result = append(result, url)
|
||||||
|
|||||||
@@ -266,6 +266,8 @@ func (s *AntigravityGatewayService) TestConnection(ctx context.Context, account
|
|||||||
// 解析流式响应,提取文本
|
// 解析流式响应,提取文本
|
||||||
text := extractTextFromSSEResponse(respBody)
|
text := extractTextFromSSEResponse(respBody)
|
||||||
|
|
||||||
|
// 标记成功的 URL,下次优先使用
|
||||||
|
antigravity.DefaultURLAvailability.MarkSuccess(baseURL)
|
||||||
return &TestConnectionResult{
|
return &TestConnectionResult{
|
||||||
Text: text,
|
Text: text,
|
||||||
MappedModel: mappedModel,
|
MappedModel: mappedModel,
|
||||||
@@ -551,8 +553,10 @@ func (s *AntigravityGatewayService) Forward(ctx context.Context, c *gin.Context,
|
|||||||
|
|
||||||
// 重试循环
|
// 重试循环
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
|
var usedBaseURL string // 追踪成功使用的 URL
|
||||||
urlFallbackLoop:
|
urlFallbackLoop:
|
||||||
for urlIdx, baseURL := range availableURLs {
|
for urlIdx, baseURL := range availableURLs {
|
||||||
|
usedBaseURL = baseURL
|
||||||
for attempt := 1; attempt <= antigravityMaxRetries; attempt++ {
|
for attempt := 1; attempt <= antigravityMaxRetries; attempt++ {
|
||||||
// 检查 context 是否已取消(客户端断开连接)
|
// 检查 context 是否已取消(客户端断开连接)
|
||||||
select {
|
select {
|
||||||
@@ -628,6 +632,11 @@ urlFallbackLoop:
|
|||||||
}
|
}
|
||||||
defer func() { _ = resp.Body.Close() }()
|
defer func() { _ = resp.Body.Close() }()
|
||||||
|
|
||||||
|
// 请求成功,标记 URL 供后续优先使用
|
||||||
|
if resp.StatusCode < 400 && usedBaseURL != "" {
|
||||||
|
antigravity.DefaultURLAvailability.MarkSuccess(usedBaseURL)
|
||||||
|
}
|
||||||
|
|
||||||
if resp.StatusCode >= 400 {
|
if resp.StatusCode >= 400 {
|
||||||
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 2<<20))
|
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 2<<20))
|
||||||
|
|
||||||
@@ -1097,8 +1106,10 @@ func (s *AntigravityGatewayService) ForwardGemini(ctx context.Context, c *gin.Co
|
|||||||
|
|
||||||
// 重试循环
|
// 重试循环
|
||||||
var resp *http.Response
|
var resp *http.Response
|
||||||
|
var usedBaseURL string // 追踪成功使用的 URL
|
||||||
urlFallbackLoop:
|
urlFallbackLoop:
|
||||||
for urlIdx, baseURL := range availableURLs {
|
for urlIdx, baseURL := range availableURLs {
|
||||||
|
usedBaseURL = baseURL
|
||||||
for attempt := 1; attempt <= antigravityMaxRetries; attempt++ {
|
for attempt := 1; attempt <= antigravityMaxRetries; attempt++ {
|
||||||
// 检查 context 是否已取消(客户端断开连接)
|
// 检查 context 是否已取消(客户端断开连接)
|
||||||
select {
|
select {
|
||||||
@@ -1177,6 +1188,11 @@ urlFallbackLoop:
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// 请求成功,标记 URL 供后续优先使用
|
||||||
|
if resp.StatusCode < 400 && usedBaseURL != "" {
|
||||||
|
antigravity.DefaultURLAvailability.MarkSuccess(usedBaseURL)
|
||||||
|
}
|
||||||
|
|
||||||
// 处理错误响应
|
// 处理错误响应
|
||||||
if resp.StatusCode >= 400 {
|
if resp.StatusCode >= 400 {
|
||||||
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 2<<20))
|
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 2<<20))
|
||||||
|
|||||||
Reference in New Issue
Block a user