fix(rate-limit): _is_rate_limited 识别 RetryError 的 429 形态,登录 429 真正触发自动退避
生产实测:登录时 garth 把 429 折进 RetryError('too many 429 error responses'),无 status_code、无 'rate limit' 字样,旧检测漏判 → 走 else 分支存原始报错、不调 _note_rate_limit,冷却永远不落库,用户可反复撞 Garmin。\n\n- garmin.py: _is_rate_limited 沿 __cause__ 链找 429 响应,并接受文本中的 '429' 标记。\n- garmin_auth.py: 退避文案 6h 改为 24h。\n- 生产:已补挂 24h 冷却(2026-08-30 10:00 北京),RetryError 形状验证识别为 429。
This commit is contained in:
@@ -204,8 +204,22 @@ def _is_rate_limited(e):
|
|||||||
if response is not None and getattr(response, "status_code", None) == 429:
|
if response is not None and getattr(response, "status_code", None) == 429:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
haystacks = [str(e), str(getattr(e, "doc", "") or "")]
|
# The 429 can be buried several layers down: garth/urllib3 fold the final
|
||||||
return any("rate limit" in h.lower() for h in haystacks)
|
# 429 into a RetryError whose message is 'too many 429 error responses' —
|
||||||
|
# no status code survives and the words "rate limit" never appear. Walk the
|
||||||
|
# cause chain and also accept the "429" marker itself.
|
||||||
|
seen = set()
|
||||||
|
cur = e
|
||||||
|
while cur is not None and id(cur) not in seen:
|
||||||
|
seen.add(id(cur))
|
||||||
|
response = getattr(cur, "response", None)
|
||||||
|
if response is not None and getattr(response, "status_code", None) == 429:
|
||||||
|
return True
|
||||||
|
text = f"{cur} {getattr(cur, 'doc', '') or ''}"
|
||||||
|
if "429" in text or "rate limit" in text.lower():
|
||||||
|
return True
|
||||||
|
cur = getattr(cur, "__cause__", None) or getattr(cur, "__context__", None)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
class MFARequired(RuntimeError):
|
class MFARequired(RuntimeError):
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ def _run_login(session_id, user_id, garmin_email, password, is_cn, import_garmin
|
|||||||
if garmin_svc._is_rate_limited(e):
|
if garmin_svc._is_rate_limited(e):
|
||||||
garmin_svc._note_rate_limit(user_id)
|
garmin_svc._note_rate_limit(user_id)
|
||||||
error = (
|
error = (
|
||||||
"Garmin 返回 429 限流(登录接口)。已自动退避 6 小时,"
|
"Garmin 返回 429 限流(登录接口)。已自动退避 24 小时,"
|
||||||
"请等待冷却窗口结束后再试——反复尝试会越撞越久。"
|
"请等待冷却窗口结束后再试——反复尝试会越撞越久。"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user