fix: 连接阶段真实 429 以 rate_limited 状态呈现,而非泛化 error
sync_data 的 _connect 抛 RateLimited(真实 429,冷却已写入)原本落进 except Exception 返回 status=error,message 带 'RateLimited:' 前缀——前端 SettingsPage 只对 status=rate_limited 渲染'被限流'提示,导致放开本地拦截 后真实 429 的提示错位。 单独捕获 RateLimited:status=rate_limited + 干净 message + history 记录 rate_limited。补测试 test_a_real_429_at_connect_surfaces_as_rate_limited (597 passed)
This commit is contained in:
@@ -1111,6 +1111,20 @@ def sync_data(user_id, creds, days=None, client=None, trigger="manual"):
|
||||
|
||||
try:
|
||||
client = client or _connect(creds, user_id)
|
||||
except RateLimited as e:
|
||||
# A genuine 429 at connect time: _connect already wrote the fresh
|
||||
# cooldown, so surface this as rate_limited (the UI draws a distinct
|
||||
# stand-down state for it) rather than a generic error.
|
||||
message = str(e)
|
||||
_set_sync_status(user_id, "rate_limited", now, records_synced=0,
|
||||
last_error=message)
|
||||
return finish({
|
||||
"status": "rate_limited",
|
||||
"recordsSynced": 0,
|
||||
"message": message,
|
||||
"mfaRequired": False,
|
||||
"lastSyncTime": now,
|
||||
})
|
||||
except Exception as e:
|
||||
message = describe(e)
|
||||
_set_sync_status(user_id, "error", now, records_synced=0, last_error=message)
|
||||
|
||||
@@ -745,6 +745,26 @@ class TestRateLimiting:
|
||||
garmin_svc._connect({}, user_id=user["id"])
|
||||
assert calls == [], "an unexpired token needs no refresh"
|
||||
|
||||
def test_a_real_429_at_connect_surfaces_as_rate_limited(self, db, user, monkeypatch):
|
||||
"""A genuine 429 while connecting is a stand-down, not a generic
|
||||
failure: sync_data must report status rate_limited so the UI draws the
|
||||
distinct '被限流' state instead of a plain error."""
|
||||
def throttled(_creds, _uid=None):
|
||||
garmin_svc._note_rate_limit(user["id"]) # what _connect does on 429
|
||||
raise garmin_svc.RateLimited(
|
||||
"Garmin 暂时限制了请求频率。这通常是短时间内连接过于频繁,"
|
||||
"等待约半小时后会自动恢复,令牌本身没有失效。"
|
||||
)
|
||||
|
||||
monkeypatch.setattr(garmin_svc, "_connect", throttled)
|
||||
out = garmin_svc.sync_data(user["id"], CREDS, days=1)
|
||||
|
||||
assert out["status"] == "rate_limited"
|
||||
assert "令牌本身没有失效" in out["message"]
|
||||
assert garmin_svc.get_sync_status(user["id"])["status"] == "rate_limited"
|
||||
assert garmin_svc.get_sync_history(user["id"])[0]["status"] == "rate_limited"
|
||||
garmin_svc._rate_limited_until.clear()
|
||||
|
||||
def test_a_valid_token_is_not_refreshed(self, db, user, monkeypatch):
|
||||
"""Refreshing on every connect spends quota for nothing — and that is
|
||||
what walked the account into a 429 in the first place."""
|
||||
|
||||
Reference in New Issue
Block a user