fix(auth): add retry logic for 429 status with Retry-After and improve testing
This commit is contained in:
@@ -1850,6 +1850,50 @@ func (m *Manager) closestCooldownWait(providers []string, model string, attempt
|
||||
return minWait, found
|
||||
}
|
||||
|
||||
func (m *Manager) retryAllowed(attempt int, providers []string) bool {
|
||||
if m == nil || attempt < 0 || len(providers) == 0 {
|
||||
return false
|
||||
}
|
||||
defaultRetry := int(m.requestRetry.Load())
|
||||
if defaultRetry < 0 {
|
||||
defaultRetry = 0
|
||||
}
|
||||
providerSet := make(map[string]struct{}, len(providers))
|
||||
for i := range providers {
|
||||
key := strings.TrimSpace(strings.ToLower(providers[i]))
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
providerSet[key] = struct{}{}
|
||||
}
|
||||
if len(providerSet) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
for _, auth := range m.auths {
|
||||
if auth == nil {
|
||||
continue
|
||||
}
|
||||
providerKey := strings.TrimSpace(strings.ToLower(auth.Provider))
|
||||
if _, ok := providerSet[providerKey]; !ok {
|
||||
continue
|
||||
}
|
||||
effectiveRetry := defaultRetry
|
||||
if override, ok := auth.RequestRetryOverride(); ok {
|
||||
effectiveRetry = override
|
||||
}
|
||||
if effectiveRetry < 0 {
|
||||
effectiveRetry = 0
|
||||
}
|
||||
if attempt < effectiveRetry {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (m *Manager) shouldRetryAfterError(err error, attempt int, providers []string, model string, maxWait time.Duration) (time.Duration, bool) {
|
||||
if err == nil {
|
||||
return 0, false
|
||||
@@ -1857,17 +1901,31 @@ func (m *Manager) shouldRetryAfterError(err error, attempt int, providers []stri
|
||||
if maxWait <= 0 {
|
||||
return 0, false
|
||||
}
|
||||
if status := statusCodeFromError(err); status == http.StatusOK {
|
||||
status := statusCodeFromError(err)
|
||||
if status == http.StatusOK {
|
||||
return 0, false
|
||||
}
|
||||
if isRequestInvalidError(err) {
|
||||
return 0, false
|
||||
}
|
||||
wait, found := m.closestCooldownWait(providers, model, attempt)
|
||||
if !found || wait > maxWait {
|
||||
if found {
|
||||
if wait > maxWait {
|
||||
return 0, false
|
||||
}
|
||||
return wait, true
|
||||
}
|
||||
if status != http.StatusTooManyRequests {
|
||||
return 0, false
|
||||
}
|
||||
return wait, true
|
||||
if !m.retryAllowed(attempt, providers) {
|
||||
return 0, false
|
||||
}
|
||||
retryAfter := retryAfterFromError(err)
|
||||
if retryAfter == nil || *retryAfter <= 0 || *retryAfter > maxWait {
|
||||
return 0, false
|
||||
}
|
||||
return *retryAfter, true
|
||||
}
|
||||
|
||||
func waitForCooldown(ctx context.Context, wait time.Duration) error {
|
||||
|
||||
Reference in New Issue
Block a user