From d11b059943776a2ed1656d49abfe8b6fc0bbe949 Mon Sep 17 00:00:00 2001 From: piexian <64474352+piexian@users.noreply.github.com> Date: Tue, 10 Feb 2026 18:36:19 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20Token=20=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=88=B7=E6=96=B0=E5=A4=B1=E8=B4=A5=E5=AF=BC=E8=87=B4?= =?UTF-8?q?=E6=8C=81=E7=BB=AD=20504/429=20=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 Scheduler 刷新使用错误的默认模型名 (grok-4-1-thinking-1129 → grok-3), 避免 basic token 查询配额时返回 403 - 调整 Scheduler 启动后立即执行首轮刷新,而非等待整个 interval (2-8h) - 移除刷新失败分支中的 mark_synced() 调用,使失败 token 在下一轮 循环中被重新尝试而非被跳过 - Token 池耗尽时自动触发 refresh_cooling_tokens(),尝试恢复 冷却中的 token,而非直接返回 429 --- app/services/grok/services/chat.py | 21 +++++++++++++++------ app/services/token/manager.py | 6 +----- app/services/token/scheduler.py | 5 ++++- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/app/services/grok/services/chat.py b/app/services/grok/services/chat.py index dcd36cc..ea88209 100644 --- a/app/services/grok/services/chat.py +++ b/app/services/grok/services/chat.py @@ -394,12 +394,21 @@ class ChatService: break if not token: - raise AppException( - message="No available tokens. Please try again later.", - error_type=ErrorType.RATE_LIMIT.value, - code="rate_limit_exceeded", - status_code=429, - ) + logger.info("No available tokens, attempting to refresh cooling tokens...") + result = await token_mgr.refresh_cooling_tokens() + if result.get("recovered", 0) > 0: + for pool_name in ModelService.pool_candidates_for_model(model): + token = token_mgr.get_token(pool_name) + if token: + break + + if not token: + raise AppException( + message="No available tokens. Please try again later.", + error_type=ErrorType.RATE_LIMIT.value, + code="rate_limit_exceeded", + status_code=429, + ) # 解析参数 think = {"enabled": True, "disabled": False}.get(thinking) diff --git a/app/services/token/manager.py b/app/services/token/manager.py index b5e28f1..d72cbd4 100644 --- a/app/services/token/manager.py +++ b/app/services/token/manager.py @@ -646,7 +646,7 @@ class TokenManager: # 重试逻辑:最多 2 次重试 for retry in range(3): # 0, 1, 2 try: - result = await usage_service.get(token_str) + result = await usage_service.get(token_str, model_name="grok-3") if result and "remainingTokens" in result: new_quota = result["remainingTokens"] @@ -666,7 +666,6 @@ class TokenManager: "expired": False, } - token_info.mark_synced() return {"recovered": False, "expired": False} except Exception as e: @@ -688,16 +687,13 @@ class TokenManager: f"marking as expired" ) token_info.status = TokenStatus.EXPIRED - token_info.mark_synced() return {"recovered": False, "expired": True} else: logger.warning( f"Token {token_info.token[:10]}...: refresh failed ({e})" ) - token_info.mark_synced() return {"recovered": False, "expired": False} - token_info.mark_synced() return {"recovered": False, "expired": False} # 批量处理 diff --git a/app/services/token/scheduler.py b/app/services/token/scheduler.py index ad4da7a..1427713 100644 --- a/app/services/token/scheduler.py +++ b/app/services/token/scheduler.py @@ -23,7 +23,6 @@ class TokenRefreshScheduler: while self._running: try: - await asyncio.sleep(self.interval_seconds) storage = get_storage() lock_acquired = False lock = None @@ -44,6 +43,7 @@ class TokenRefreshScheduler: if not lock_acquired: logger.info("Scheduler: skipped (lock not acquired)") + await asyncio.sleep(self.interval_seconds) continue try: @@ -65,10 +65,13 @@ class TokenRefreshScheduler: except Exception: pass + await asyncio.sleep(self.interval_seconds) + except asyncio.CancelledError: break except Exception as e: logger.error(f"Scheduler: refresh error - {e}") + await asyncio.sleep(self.interval_seconds) def start(self): """启动调度器"""