fix(sync): 「全部历史」真的拉全部历史,自动同步不再每次静默失败
四个独立的 bug 叠在一起,表现为「只同步两天、没有进度」:
* 前端 `...(days ? { days } : {})` 把 days=0 当成未传。「全部历史」
存的就是 0,请求体里根本没有 days,后端退回 7 天默认值。
* scheduler 用 `s[0]` 读 query_one 返回的 dict,抛 KeyError 后被
per-account 的 except 吞掉。只要用户存过一次设置,每 30 分钟的
自动同步就一次都没成功过——库里那 2 天全是手动点出来的。
* 增量同步查 `health_daily`(表其实叫 health_data),后台线程直接
死掉,状态永远卡在 syncing,进度条不动。
* UI 完全不看 /sync 的返回值,rate_limited 时按钮点了没反应;轮询
结束时又把 rate_limited 归进 else 分支报「同步完成」。
顺带:
* 日循环遇到 429 立即退避并保留已拉到的天数,而不是当成「跳过一天」
继续往下捶 700 天——这正是之前限流死循环的来源之一。
* 定时循环显式传 SYNC_DAYS。历史范围按 UI 文案只描述手动全量同步,
让半小时一次的 tick 重拉 730 天必然把限流撞得更深。
* 短同步逐天上报进度(原来每 5 天一次,7 天的同步全程停在 0)。
* /sync 路由重复解析 body,空 body 会 None.get 崩。
* 4 个 StubGarth 缺 configure(),7 个测试在此之前一直是红的。
新增 deploy/push.sh:NAS 只认密码,脚本开一个 ssh 复用连接,密码只
输一次,后面推送 / 重启 / 健康检查全走它。不碰 .env、.venv 和数据库。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -218,8 +218,14 @@ function SyncPage() {
|
||||
setLoading(true);
|
||||
try {
|
||||
// 0 means "everything"; the backend caps it at what Garmin will serve.
|
||||
await apiClient.syncGarminData(settings?.historyDays ?? 3650);
|
||||
await refresh();
|
||||
const started = await apiClient.syncGarminData(settings?.historyDays ?? 365);
|
||||
const s = await refresh();
|
||||
// A refused start (Garmin is throttling us) used to be swallowed: the
|
||||
// button did nothing, no progress bar appeared, and no reason was shown.
|
||||
if (started.status === 'rate_limited' || s?.status === 'rate_limited') {
|
||||
setError(started.message || s?.lastError || 'Garmin 正在限流,稍后会自动恢复。');
|
||||
return;
|
||||
}
|
||||
beginSyncPolling();
|
||||
} catch (err: any) {
|
||||
setError(errorMessage(err, '同步失败'));
|
||||
@@ -265,8 +271,10 @@ function SyncPage() {
|
||||
if (!s) { stopPolling(); return; }
|
||||
if (s.status !== 'syncing') {
|
||||
stopPolling();
|
||||
if (s.status === 'error') setError(s.lastError || '同步失败');
|
||||
else setMessage(`同步完成,已更新 ${s.recordsSynced} 天数据`);
|
||||
// Only 'idle' means it finished; anything else reported "同步完成"
|
||||
// while nothing had been synced.
|
||||
if (s.status === 'idle') setMessage(`同步完成,已更新 ${s.recordsSynced} 天数据`);
|
||||
else setError(s.lastError || '同步失败');
|
||||
}
|
||||
}, POLL_MS);
|
||||
};
|
||||
@@ -374,7 +382,9 @@ function SyncPage() {
|
||||
<section className="sync-card">
|
||||
<div className="progress-head">
|
||||
<span>{syncStatus?.stage || '正在同步…'}</span>
|
||||
<span className="progress-count">{current} / {total} 天</span>
|
||||
<span className="progress-count">
|
||||
{total > 0 ? `${current} / ${total} 天` : `${current} 天`}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className="progress-bar"
|
||||
|
||||
Reference in New Issue
Block a user