[PR #241] [MERGED] feat(kiro): 改进错误处理逻辑,添加配额耗尽自动恢复机制 #316

Closed
opened 2026-02-27 07:18:56 +03:00 by kerem · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/justlovemaki/AIClient-2-API/pull/241
Author: @leonaii
Created: 1/14/2026
Status: Merged
Merged: 1/14/2026
Merged by: @justlovemaki

Base: mainHead: main


📝 Commits (3)

📊 Changes

3 files changed (+258 additions, -31 deletions)

View changed files

📝 src/providers/claude/claude-kiro.js (+137 -25)
📝 src/providers/provider-pool-manager.js (+89 -0)
📝 src/utils/common.js (+32 -6)

📄 Description

🎯 问题描述

背景

Kiro Provider 在处理 API 错误时存在以下问题:

  1. scheduledRecoveryTime 字段未生效:虽然设置了该字段,但没有检查和自动恢复的逻辑,导致配额耗尽的凭证无法在下月自动恢复
  2. 潜在的无限循环风险:当所有凭证都返回 429/5xx 错误时,可能导致无限重试
  3. 重复代码callApi()streamApiReal() 中有约 25 行重复的 402 错误处理代码
  4. 魔法数字:下月 1 日的计算逻辑在多处重复出现

影响

  • 配额耗尽的 Kiro 凭证需要手动恢复,无法自动在下月 1 日重置
  • 在极端情况下可能导致请求处理卡死
  • 代码可维护性较差

解决方案

1. 添加 scheduledRecoveryTime 自动恢复机制 (高优先级)

provider-pool-manager.js 中新增 _checkAndRecoverScheduledProviders() 方法:

  • 检查所有提供商的 scheduledRecoveryTime 字段
  • 如果当前时间已超过恢复时间,自动将提供商标记为健康
  • selectProvider()performHealthChecks() 中调用
_checkAndRecoverScheduledProviders(providerType = null) {
    const now = new Date();
    for (const providerStatus of providers) {
        if (config.scheduledRecoveryTime && !config.isHealthy) {
            if (now >= new Date(config.scheduledRecoveryTime)) {
                config.isHealthy = true;
                config.errorCount = 0;
                config.scheduledRecoveryTime = null;
                this._debouncedSave(type);
            }
        }
    }
}

2. 改进凭证切换逻辑 (高优先级)

  • 429/5xx 错误不再在底层重试,而是通过 shouldSwitchCredential 标记触发凭证切换
  • 使用 skipErrorCount 标记避免对临时错误(429/5xx)增加错误计数
  • 凭证切换次数由现有配置 CREDENTIAL_SWITCH_MAX_RETRIES(默认 5)控制

3. 提取重复的 402 处理逻辑 (中优先级)

新增 _handle402Error() 私有方法,统一处理 402 错误:

  • 验证配额使用情况
  • 计算下月 1 日恢复时间
  • 标记凭证为不健康并设置恢复时间

4. 提取下月 1 日计算方法 (低优先级)

新增 _getNextMonthFirstDay() 方法,消除魔法数字:

_getNextMonthFirstDay() {
    const now = new Date();
    return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1, 0, 0, 0, 0));
}

5. 创建自定义错误类 (低优先级)

新增 CredentialError 类,为后续重构提供基础:

class CredentialError extends Error {
    constructor(message, options = {}) {
        super(message);
        this.name = 'CredentialError';
        this.shouldSwitchCredential = options.shouldSwitchCredential ?? false;
        this.skipErrorCount = options.skipErrorCount ?? false;
        this.credentialMarkedUnhealthy = options.credentialMarkedUnhealthy ?? false;
        this.statusCode = options.statusCode;
        this.originalError = options.originalError;
    }
}

📁 改动文件

文件 改动类型 说明
src/providers/claude/claude-kiro.js 修改 新增 CredentialError 类、_getNextMonthFirstDay()_handle402Error() 方法;改进 429/5xx 错误处理
src/providers/provider-pool-manager.js 修改 新增 _checkAndRecoverScheduledProviders()markProviderUnhealthyWithRecoveryTime() 方法
src/utils/common.js 修改 支持 skipErrorCountshouldSwitchCredential 标记

统计:3 个文件,+258 行,-31 行


🧪 测试说明

手动测试场景

  1. 402 配额耗尽测试

    • 触发 402 错误后,检查凭证是否被标记为不健康
    • 检查 scheduledRecoveryTime 是否设置为下月 1 日
    • 模拟时间到达恢复时间后,检查凭证是否自动恢复
  2. 429 限流测试

    • 触发 429 错误后,检查是否切换到其他凭证
    • 检查原凭证的 errorCount 是否未增加
  3. 5xx 服务器错误测试

    • 触发 5xx 错误后,检查是否切换到其他凭证
    • 检查重试次数是否受 CREDENTIAL_SWITCH_MAX_RETRIES 限制
  4. 凭证池耗尽测试

    • 所有凭证都返回错误时,检查是否在达到最大重试次数后停止
    • 检查是否返回适当的错误信息

⚠️ 破坏性变更

无破坏性变更

  • 所有新增方法都是私有方法或可选参数
  • 现有配置 CREDENTIAL_SWITCH_MAX_RETRIES 继续生效
  • 错误处理行为更加合理,但不影响现有 API 接口

🔍 代码审查要点

  1. _checkAndRecoverScheduledProviders() 的调用时机是否合适?
  2. skipErrorCountshouldSwitchCredential 的命名是否清晰?
  3. 是否需要为 CredentialError 类添加更多使用场景?

📊 性能影响

  • _checkAndRecoverScheduledProviders(): O(n),n 为提供商数量(通常 < 10),每次调用 < 0.1ms
  • 无额外网络请求
  • 使用 _debouncedSave() 避免频繁文件 I/O

结论:无明显性能影响


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/justlovemaki/AIClient-2-API/pull/241 **Author:** [@leonaii](https://github.com/leonaii) **Created:** 1/14/2026 **Status:** ✅ Merged **Merged:** 1/14/2026 **Merged by:** [@justlovemaki](https://github.com/justlovemaki) **Base:** `main` ← **Head:** `main` --- ### 📝 Commits (3) - [`47e4e49`](https://github.com/justlovemaki/AIClient-2-API/commit/47e4e493ec4ecd3b5a14b94fbc87a8dccd4650db) feat(kiro): 添加凭证错误处理和配额恢复机制 - [`536f5f2`](https://github.com/justlovemaki/AIClient-2-API/commit/536f5f22eb677f33bc1c9985cf9afe78dbafee48) Merge branch 'main' of https://github.com/leonaii/AIClient-2-API - [`694cafc`](https://github.com/justlovemaki/AIClient-2-API/commit/694cafcac7789e03e33e92b2074c50463a9eee4a) Merge branch 'justlovemaki:main' into main ### 📊 Changes **3 files changed** (+258 additions, -31 deletions) <details> <summary>View changed files</summary> 📝 `src/providers/claude/claude-kiro.js` (+137 -25) 📝 `src/providers/provider-pool-manager.js` (+89 -0) 📝 `src/utils/common.js` (+32 -6) </details> ### 📄 Description ## 🎯 问题描述 ### 背景 Kiro Provider 在处理 API 错误时存在以下问题: 1. **`scheduledRecoveryTime` 字段未生效**:虽然设置了该字段,但没有检查和自动恢复的逻辑,导致配额耗尽的凭证无法在下月自动恢复 2. **潜在的无限循环风险**:当所有凭证都返回 429/5xx 错误时,可能导致无限重试 3. **重复代码**:`callApi()` 和 `streamApiReal()` 中有约 25 行重复的 402 错误处理代码 4. **魔法数字**:下月 1 日的计算逻辑在多处重复出现 ### 影响 - 配额耗尽的 Kiro 凭证需要手动恢复,无法自动在下月 1 日重置 - 在极端情况下可能导致请求处理卡死 - 代码可维护性较差 --- ## ✅ 解决方案 ### 1. 添加 `scheduledRecoveryTime` 自动恢复机制 (高优先级) 在 `provider-pool-manager.js` 中新增 `_checkAndRecoverScheduledProviders()` 方法: - 检查所有提供商的 `scheduledRecoveryTime` 字段 - 如果当前时间已超过恢复时间,自动将提供商标记为健康 - 在 `selectProvider()` 和 `performHealthChecks()` 中调用 ```javascript _checkAndRecoverScheduledProviders(providerType = null) { const now = new Date(); for (const providerStatus of providers) { if (config.scheduledRecoveryTime && !config.isHealthy) { if (now >= new Date(config.scheduledRecoveryTime)) { config.isHealthy = true; config.errorCount = 0; config.scheduledRecoveryTime = null; this._debouncedSave(type); } } } } ``` ### 2. 改进凭证切换逻辑 (高优先级) - 429/5xx 错误不再在底层重试,而是通过 `shouldSwitchCredential` 标记触发凭证切换 - 使用 `skipErrorCount` 标记避免对临时错误(429/5xx)增加错误计数 - 凭证切换次数由现有配置 `CREDENTIAL_SWITCH_MAX_RETRIES`(默认 5)控制 ### 3. 提取重复的 402 处理逻辑 (中优先级) 新增 `_handle402Error()` 私有方法,统一处理 402 错误: - 验证配额使用情况 - 计算下月 1 日恢复时间 - 标记凭证为不健康并设置恢复时间 ### 4. 提取下月 1 日计算方法 (低优先级) 新增 `_getNextMonthFirstDay()` 方法,消除魔法数字: ```javascript _getNextMonthFirstDay() { const now = new Date(); return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth() + 1, 1, 0, 0, 0, 0)); } ``` ### 5. 创建自定义错误类 (低优先级) 新增 `CredentialError` 类,为后续重构提供基础: ```javascript class CredentialError extends Error { constructor(message, options = {}) { super(message); this.name = 'CredentialError'; this.shouldSwitchCredential = options.shouldSwitchCredential ?? false; this.skipErrorCount = options.skipErrorCount ?? false; this.credentialMarkedUnhealthy = options.credentialMarkedUnhealthy ?? false; this.statusCode = options.statusCode; this.originalError = options.originalError; } } ``` --- ## 📁 改动文件 | 文件 | 改动类型 | 说明 | |------|----------|------| | `src/providers/claude/claude-kiro.js` | 修改 | 新增 `CredentialError` 类、`_getNextMonthFirstDay()`、`_handle402Error()` 方法;改进 429/5xx 错误处理 | | `src/providers/provider-pool-manager.js` | 修改 | 新增 `_checkAndRecoverScheduledProviders()`、`markProviderUnhealthyWithRecoveryTime()` 方法 | | `src/utils/common.js` | 修改 | 支持 `skipErrorCount` 和 `shouldSwitchCredential` 标记 | **统计**:3 个文件,+258 行,-31 行 --- ## 🧪 测试说明 ### 手动测试场景 1. **402 配额耗尽测试** - 触发 402 错误后,检查凭证是否被标记为不健康 - 检查 `scheduledRecoveryTime` 是否设置为下月 1 日 - 模拟时间到达恢复时间后,检查凭证是否自动恢复 2. **429 限流测试** - 触发 429 错误后,检查是否切换到其他凭证 - 检查原凭证的 `errorCount` 是否未增加 3. **5xx 服务器错误测试** - 触发 5xx 错误后,检查是否切换到其他凭证 - 检查重试次数是否受 `CREDENTIAL_SWITCH_MAX_RETRIES` 限制 4. **凭证池耗尽测试** - 所有凭证都返回错误时,检查是否在达到最大重试次数后停止 - 检查是否返回适当的错误信息 --- ## ⚠️ 破坏性变更 **无破坏性变更** - 所有新增方法都是私有方法或可选参数 - 现有配置 `CREDENTIAL_SWITCH_MAX_RETRIES` 继续生效 - 错误处理行为更加合理,但不影响现有 API 接口 --- ## 🔍 代码审查要点 1. `_checkAndRecoverScheduledProviders()` 的调用时机是否合适? 2. `skipErrorCount` 和 `shouldSwitchCredential` 的命名是否清晰? 3. 是否需要为 `CredentialError` 类添加更多使用场景? --- ## 📊 性能影响 - `_checkAndRecoverScheduledProviders()`: O(n),n 为提供商数量(通常 < 10),每次调用 < 0.1ms - 无额外网络请求 - 使用 `_debouncedSave()` 避免频繁文件 I/O **结论**:无明显性能影响 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
kerem 2026-02-27 07:18:56 +03:00
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/AIClient-2-API-justlovemaki#316
No description provided.