fix(sync): 限流拦截不再把'上次同步'刷成现在 + 设置页新增立即同步按钮

- _set_sync_status 支持保留旧 last_sync_time;两处限流拦截(start_sync /
  sync_data)改为传旧值——被拒的同步零请求发生,不能把 UI 的'上次同步'
  拨快成'刚刚',掩盖数据早已停更的事实
- SettingsPage 同步区块新增'立即同步'行:走 /garmin/sync-latest(最近2天,
  秒级阻塞返回),成功/限流/未绑定三种状态都有明确反馈;限流中后端零请求
  拦截并回传恢复倒计时文案
This commit is contained in:
ericwyuan
2026-09-02 20:14:11 +08:00
parent 2d9a2be185
commit 224144915c
2 changed files with 71 additions and 3 deletions

View File

@@ -34,7 +34,15 @@ from services import garmin_extras as extras
DEFAULT_SYNC_DAYS = int(os.environ.get("GARMIN_SYNC_DAYS") or 7)
def _set_sync_status(user_id, status, now, **fields):
def _set_sync_status(user_id, status, now, last_sync_time=None, **fields):
"""Write the status row; `now` becomes the new last_sync_time by default.
Callers that merely *report* being blocked (a rate-limit refusal, a
refused start) pass the previous last_sync_time explicitly: a sync that
never happened must not move "上次同步" forward, or the UI reads "刚刚"
while the data actually stopped syncing hours ago.
"""
last = last_sync_time if last_sync_time is not None else now
cols = ["user_id", "status", "last_sync_time"] + list(fields.keys())
placeholders = ", ".join(["?"] * len(cols))
if DB_TYPE == "mariadb":
@@ -49,7 +57,7 @@ def _set_sync_status(user_id, status, now, **fields):
f"INSERT INTO sync_status ({', '.join(cols)}) VALUES ({placeholders}) "
f"ON CONFLICT(user_id) DO UPDATE SET {updates}"
)
execute(sql, [user_id, status, now] + list(fields.values()))
execute(sql, [user_id, status, last] + list(fields.values()))
def get_sync_status(user_id):
@@ -971,8 +979,15 @@ def start_sync(user_id, creds, days=None):
now = datetime.datetime.utcnow().isoformat(timespec="seconds")
until, msg = _rate_limit_block(user_id)
if until:
# A refused start synced nothing — keep the previous last_sync_time so
# the UI's 上次同步 keeps telling the truth (the data is stale since
# the last *successful* sync, and that date is what the user needs).
row = query_one(
"SELECT last_sync_time FROM sync_status WHERE user_id = ?", [user_id]
)
_set_sync_status(
user_id, "rate_limited", now,
last_sync_time=row["last_sync_time"] if row else None,
records_synced=0, progress_current=0, progress_total=days,
started_at=now, last_error=msg,
)
@@ -1005,9 +1020,14 @@ def sync_data(user_id, creds, days=None, client=None):
until, msg = _rate_limit_block(user_id)
if until:
# A blocked account must issue zero Garmin requests — that is the whole
# point. Return immediately without touching the network.
# point. Return immediately without touching the network, and keep the
# previous last_sync_time (this was not a sync).
row = query_one(
"SELECT last_sync_time FROM sync_status WHERE user_id = ?", [user_id]
)
_set_sync_status(
user_id, "rate_limited", now,
last_sync_time=row["last_sync_time"] if row else None,
records_synced=0, last_error=msg,
)
return {