feat: add client availability tracking and error handling improvements

- Introduced `IsAvailable` and `SetUnavailable` methods to clients for availability tracking.
- Integrated availability checks in client selection logic to skip unavailable clients.
- Enhanced error handling by marking clients unavailable on specific error codes (e.g., 401, 402).
- Removed redundant quota verification logs in client reordering logic.
This commit is contained in:
Luis Pater
2025-09-19 01:53:38 +08:00
parent 9ec8478b41
commit df66046b14
15 changed files with 183 additions and 21 deletions

View File

@@ -442,9 +442,13 @@ func (h *OpenAIAPIHandler) handleNonStreamingResponse(c *gin.Context, rawJSON []
errRefreshTokens := cliClient.RefreshTokens(cliCtx)
if errRefreshTokens != nil {
log.Debugf("refresh token failed, switch client, %s", util.HideAPIKey(cliClient.GetEmail()))
cliClient.SetUnavailable()
}
retryCount++
continue
case 402:
cliClient.SetUnavailable()
continue
default:
// Forward other errors directly to the client
c.Status(err.StatusCode)
@@ -557,6 +561,18 @@ outLoop:
log.Debugf("http status code %d, switch client", err.StatusCode)
retryCount++
continue outLoop
case 401:
log.Debugf("unauthorized request, try to refresh token, %s", util.HideAPIKey(cliClient.GetEmail()))
errRefreshTokens := cliClient.RefreshTokens(cliCtx)
if errRefreshTokens != nil {
log.Debugf("refresh token failed, switch client, %s", util.HideAPIKey(cliClient.GetEmail()))
cliClient.SetUnavailable()
}
retryCount++
continue outLoop
case 402:
cliClient.SetUnavailable()
continue outLoop
default:
// Forward other errors directly to the client
c.Status(err.StatusCode)
@@ -632,6 +648,18 @@ func (h *OpenAIAPIHandler) handleCompletionsNonStreamingResponse(c *gin.Context,
log.Debugf("http status code %d, switch client", err.StatusCode)
retryCount++
continue
case 401:
log.Debugf("unauthorized request, try to refresh token, %s", util.HideAPIKey(cliClient.GetEmail()))
errRefreshTokens := cliClient.RefreshTokens(cliCtx)
if errRefreshTokens != nil {
log.Debugf("refresh token failed, switch client, %s", util.HideAPIKey(cliClient.GetEmail()))
cliClient.SetUnavailable()
}
retryCount++
continue
case 402:
cliClient.SetUnavailable()
continue
default:
// Forward other errors directly to the client
c.Status(err.StatusCode)
@@ -755,6 +783,18 @@ outLoop:
log.Debugf("http status code %d, switch client", err.StatusCode)
retryCount++
continue outLoop
case 401:
log.Debugf("unauthorized request, try to refresh token, %s", util.HideAPIKey(cliClient.GetEmail()))
errRefreshTokens := cliClient.RefreshTokens(cliCtx)
if errRefreshTokens != nil {
log.Debugf("refresh token failed, switch client, %s", util.HideAPIKey(cliClient.GetEmail()))
cliClient.SetUnavailable()
}
retryCount++
continue outLoop
case 402:
cliClient.SetUnavailable()
continue outLoop
default:
// Forward other errors directly to the client
c.Status(err.StatusCode)

View File

@@ -146,9 +146,13 @@ func (h *OpenAIResponsesAPIHandler) handleNonStreamingResponse(c *gin.Context, r
errRefreshTokens := cliClient.RefreshTokens(cliCtx)
if errRefreshTokens != nil {
log.Debugf("refresh token failed, switch client, %s", util.HideAPIKey(cliClient.GetEmail()))
cliClient.SetUnavailable()
}
retryCount++
continue
case 402:
cliClient.SetUnavailable()
continue
default:
// Forward other errors directly to the client
c.Status(err.StatusCode)
@@ -260,6 +264,18 @@ outLoop:
log.Debugf("http status code %d, switch client", err.StatusCode)
retryCount++
continue outLoop
case 401:
log.Debugf("unauthorized request, try to refresh token, %s", util.HideAPIKey(cliClient.GetEmail()))
errRefreshTokens := cliClient.RefreshTokens(cliCtx)
if errRefreshTokens != nil {
log.Debugf("refresh token failed, switch client, %s", util.HideAPIKey(cliClient.GetEmail()))
cliClient.SetUnavailable()
}
retryCount++
continue outLoop
case 402:
cliClient.SetUnavailable()
continue outLoop
default:
// Forward other errors directly to the client
c.Status(err.StatusCode)