[阶段7.1] 同步改为后台任务 + 进度上报,支持回补历史

趋势页提供了"一年"档,但库里只有 7 天数据,那一档形同虚设。
实测每天约 2.84 秒(一天要打 5 个端点),回补一年需要约 28 分钟,
远超任何 HTTP 超时能等的时间。

- sync_status 新增 progress_current / progress_total / started_at
- start_sync() 起后台线程并立即返回,sync_data 每 5 天写一次进度
  (写库便宜但不免费,而前端本来就是 2 秒一轮询)
- POST /api/garmin/sync 改为 202 立即返回,接受 days 参数并
  夹在 1..730;进度经 GET /status 轮询
- 一次新同步会清掉上一次的错误,避免旧错误一直挂在界面上

前端:
- 同步页给出 7 / 30 / 90 / 365 天四个选项,日常与首次回补分开
- 进度条显示"第 N / 共 M 天"与预计耗时,并说明可以离开本页
- 页面挂载时若发现正在同步会接着轮询 —— 回补比页面存活时间长,
  刷新后必须能接上进度

tests (+7, 共 299):
- start_sync 在工作完成前就返回,且返回前已把 total 写好
- 进度随同步推进,结束时等于总天数
- days 超范围被夹到 730
- 新同步清除上一次的错误

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
ericwyuan
2026-08-23 21:31:50 +08:00
parent ad88ec7e41
commit 6a5cfa7806
7 changed files with 261 additions and 32 deletions

View File

@@ -36,8 +36,16 @@ def sync():
400,
)
result = garmin_svc.sync_data(g.user_id, creds)
return jsonify(result)
days = request.get_json(silent=True).get("days") if request.is_json else None
try:
days = max(1, min(int(days), 730)) if days else None
except (TypeError, ValueError):
days = None
# Always run in the background: even a week takes ~20s, and a full
# backfill runs for many minutes. Progress is polled via /status.
result = garmin_svc.start_sync(g.user_id, creds, days)
return jsonify(result), 202
@bp.route("/auth-status", methods=["GET"])