fix(gateway): 自定义错误码触发停止调度
- 修改 HandleUpstreamError 逻辑,启用自定义错误码时所有在列表中的错误码都会停止调度 - 添加 handleCustomErrorCode 函数处理自定义错误码的账号停用 - 前端添加 429/529 错误码的警告提示,因为这些错误码已有内置处理机制 - 更新 EditAccountModal、CreateAccountModal、BulkEditAccountModal 的错误码添加逻辑
This commit is contained in:
@@ -49,6 +49,7 @@ func NewRateLimitService(accountRepo AccountRepository, usageRepo UsageLogReposi
|
||||
func (s *RateLimitService) HandleUpstreamError(ctx context.Context, account *Account, statusCode int, headers http.Header, responseBody []byte) (shouldDisable bool) {
|
||||
// apikey 类型账号:检查自定义错误码配置
|
||||
// 如果启用且错误码不在列表中,则不处理(不停止调度、不标记限流/过载)
|
||||
customErrorCodesEnabled := account.IsCustomErrorCodesEnabled()
|
||||
if !account.ShouldHandleErrorCode(statusCode) {
|
||||
log.Printf("Account %d: error %d skipped (not in custom error codes)", account.ID, statusCode)
|
||||
return false
|
||||
@@ -93,11 +94,19 @@ func (s *RateLimitService) HandleUpstreamError(ctx context.Context, account *Acc
|
||||
s.handle529(ctx, account)
|
||||
shouldDisable = false
|
||||
default:
|
||||
// 其他5xx错误:记录但不停止调度
|
||||
if statusCode >= 500 {
|
||||
// 自定义错误码启用时:在列表中的错误码都应该停止调度
|
||||
if customErrorCodesEnabled {
|
||||
msg := "Custom error code triggered"
|
||||
if upstreamMsg != "" {
|
||||
msg = upstreamMsg
|
||||
}
|
||||
s.handleCustomErrorCode(ctx, account, statusCode, msg)
|
||||
shouldDisable = true
|
||||
} else if statusCode >= 500 {
|
||||
// 未启用自定义错误码时:仅记录5xx错误
|
||||
log.Printf("Account %d received upstream error %d", account.ID, statusCode)
|
||||
shouldDisable = false
|
||||
}
|
||||
shouldDisable = false
|
||||
}
|
||||
|
||||
if tempMatched {
|
||||
@@ -273,6 +282,16 @@ func (s *RateLimitService) handleAuthError(ctx context.Context, account *Account
|
||||
log.Printf("Account %d disabled due to auth error: %s", account.ID, errorMsg)
|
||||
}
|
||||
|
||||
// handleCustomErrorCode 处理自定义错误码,停止账号调度
|
||||
func (s *RateLimitService) handleCustomErrorCode(ctx context.Context, account *Account, statusCode int, errorMsg string) {
|
||||
msg := "Custom error code " + strconv.Itoa(statusCode) + ": " + errorMsg
|
||||
if err := s.accountRepo.SetError(ctx, account.ID, msg); err != nil {
|
||||
log.Printf("SetError failed for account %d: %v", account.ID, err)
|
||||
return
|
||||
}
|
||||
log.Printf("Account %d disabled due to custom error code %d: %s", account.ID, statusCode, errorMsg)
|
||||
}
|
||||
|
||||
// handle429 处理429限流错误
|
||||
// 解析响应头获取重置时间,标记账号为限流状态
|
||||
func (s *RateLimitService) handle429(ctx context.Context, account *Account, headers http.Header) {
|
||||
|
||||
@@ -778,6 +778,16 @@ const addPresetMapping = (from: string, to: string) => {
|
||||
const toggleErrorCode = (code: number) => {
|
||||
const index = selectedErrorCodes.value.indexOf(code)
|
||||
if (index === -1) {
|
||||
// Adding code - check for 429/529 warning
|
||||
if (code === 429) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes429Warning'))) {
|
||||
return
|
||||
}
|
||||
} else if (code === 529) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes529Warning'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
selectedErrorCodes.value.push(code)
|
||||
} else {
|
||||
selectedErrorCodes.value.splice(index, 1)
|
||||
@@ -794,6 +804,16 @@ const addCustomErrorCode = () => {
|
||||
appStore.showInfo(t('admin.accounts.errorCodeExists'))
|
||||
return
|
||||
}
|
||||
// Check for 429/529 warning
|
||||
if (code === 429) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes429Warning'))) {
|
||||
return
|
||||
}
|
||||
} else if (code === 529) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes529Warning'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
selectedErrorCodes.value.push(code)
|
||||
customErrorCodeInput.value = null
|
||||
}
|
||||
|
||||
@@ -1976,6 +1976,16 @@ const addPresetMapping = (from: string, to: string) => {
|
||||
const toggleErrorCode = (code: number) => {
|
||||
const index = selectedErrorCodes.value.indexOf(code)
|
||||
if (index === -1) {
|
||||
// Adding code - check for 429/529 warning
|
||||
if (code === 429) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes429Warning'))) {
|
||||
return
|
||||
}
|
||||
} else if (code === 529) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes529Warning'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
selectedErrorCodes.value.push(code)
|
||||
} else {
|
||||
selectedErrorCodes.value.splice(index, 1)
|
||||
@@ -1993,6 +2003,16 @@ const addCustomErrorCode = () => {
|
||||
appStore.showInfo(t('admin.accounts.errorCodeExists'))
|
||||
return
|
||||
}
|
||||
// Check for 429/529 warning
|
||||
if (code === 429) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes429Warning'))) {
|
||||
return
|
||||
}
|
||||
} else if (code === 529) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes529Warning'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
selectedErrorCodes.value.push(code)
|
||||
customErrorCodeInput.value = null
|
||||
}
|
||||
|
||||
@@ -936,6 +936,16 @@ const addPresetMapping = (from: string, to: string) => {
|
||||
const toggleErrorCode = (code: number) => {
|
||||
const index = selectedErrorCodes.value.indexOf(code)
|
||||
if (index === -1) {
|
||||
// Adding code - check for 429/529 warning
|
||||
if (code === 429) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes429Warning'))) {
|
||||
return
|
||||
}
|
||||
} else if (code === 529) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes529Warning'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
selectedErrorCodes.value.push(code)
|
||||
} else {
|
||||
selectedErrorCodes.value.splice(index, 1)
|
||||
@@ -953,6 +963,16 @@ const addCustomErrorCode = () => {
|
||||
appStore.showInfo(t('admin.accounts.errorCodeExists'))
|
||||
return
|
||||
}
|
||||
// Check for 429/529 warning
|
||||
if (code === 429) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes429Warning'))) {
|
||||
return
|
||||
}
|
||||
} else if (code === 529) {
|
||||
if (!confirm(t('admin.accounts.customErrorCodes529Warning'))) {
|
||||
return
|
||||
}
|
||||
}
|
||||
selectedErrorCodes.value.push(code)
|
||||
customErrorCodeInput.value = null
|
||||
}
|
||||
|
||||
@@ -1203,6 +1203,10 @@ export default {
|
||||
customErrorCodesHint: 'Only stop scheduling for selected error codes',
|
||||
customErrorCodesWarning:
|
||||
'Only selected error codes will stop scheduling. Other errors will return 500.',
|
||||
customErrorCodes429Warning:
|
||||
'429 already has built-in rate limit handling. Adding it to custom error codes will disable the account instead of temporary rate limiting. Are you sure?',
|
||||
customErrorCodes529Warning:
|
||||
'529 already has built-in overload handling. Adding it to custom error codes will disable the account instead of temporary overload marking. Are you sure?',
|
||||
selectedErrorCodes: 'Selected',
|
||||
noneSelectedUsesDefault: 'None selected (uses default policy)',
|
||||
enterErrorCode: 'Enter error code (100-599)',
|
||||
|
||||
@@ -1339,6 +1339,10 @@ export default {
|
||||
customErrorCodes: '自定义错误码',
|
||||
customErrorCodesHint: '仅对选中的错误码停止调度',
|
||||
customErrorCodesWarning: '仅选中的错误码会停止调度,其他错误将返回 500。',
|
||||
customErrorCodes429Warning:
|
||||
'429 已有内置的限流处理机制。添加到自定义错误码后,将直接停止调度而非临时限流。确定要添加吗?',
|
||||
customErrorCodes529Warning:
|
||||
'529 已有内置的过载处理机制。添加到自定义错误码后,将直接停止调度而非临时标记过载。确定要添加吗?',
|
||||
selectedErrorCodes: '已选择',
|
||||
noneSelectedUsesDefault: '未选择(使用默认策略)',
|
||||
enterErrorCode: '输入错误码 (100-599)',
|
||||
|
||||
Reference in New Issue
Block a user