fix: 本地限流估算不再拦截同步——一律真实请求 Garmin,仅真实 429 记录冷却并退避

此前 sync_data/start_sync/_connect/scheduler 四处会在请求前按本地
rate_limited_until 估算直接拒绝同步,用户看到'立即同步→被限流'实际是
本地拦截、零请求。若 Garmin 已恢复,陈旧估算会让账号一直闲置。

2026-09-02 起冷却只是信息不是闸门:
- start_sync / sync_data 开头移除本地拒绝,_connect 移除冷却提前抛错,
  scheduler 不再跳过冷却中的账号
- 真实 429(refresh_oauth2 / 拉取中途)仍 _note_rate_limit 写 24h 冷却
  并 stand down,中途退避分支保留用冷却算恢复时间
- 成功收尾 _clear_rate_limit 退休陈旧冷却,避免误导后续诊断
- 测试:blocked→仍会真实请求;stale cooldown→healthy connect 放行;
  真实 429 mid-run 仍记 rate_limited;成功清除冷却(596 passed)
This commit is contained in:
ericwyuan
2026-09-03 07:06:12 +08:00
parent 7e8e376a6c
commit e0e7b3cf53
3 changed files with 110 additions and 76 deletions

View File

@@ -151,16 +151,10 @@ def sync_all_accounts(days=None, respect_schedule=False):
"reason": "not due"})
continue
d = SYNC_DAYS if days is None else days
# Never poke Garmin while it is rate-limiting us — that is exactly
# what keeps the limit alive. Respect the persisted cooldown and sit
# this tick out.
blocked = garmin_svc.rate_limited_until(uid)
if blocked and blocked > _now():
results.append({
"user": uid, "status": "skipped", "reason": "rate-limited",
"retryAfterSeconds": int((blocked - _now()).total_seconds()),
})
continue
# 2026-09-02: the recorded cooldown is no longer consulted before
# a sync — a stale estimate must not keep a healthy account idle,
# and only Garmin's live answer (a real 429, handled inside
# sync_data) decides whether the throttle is actually closed.
out = garmin_svc.sync_data(uid, {}, days=d, trigger="auto")
results.append({"user": uid, "status": out.get("status"),
"records": out.get("recordsSynced")})