Skip to content

Commit 5f1dcd6

Browse files
committed
fix: 缓存 API 日期加 3 天宽限期,超期降级回 today
宽限期内信任缓存(避免周末/假日误报),超过 3 天降级回 today 比较(提示可能有新数据),兼顾两端场景。
1 parent 431f785 commit 5f1dcd6

2 files changed

Lines changed: 40 additions & 9 deletions

File tree

quantclass_sync_internal/data_query.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
# 状态颜色阈值(自然日)
2121
_DAYS_YELLOW = 1 # >= 1 天落后: 黄色
2222
_DAYS_RED = 4 # >= 4 天落后: 红色
23+
# 缓存宽限期:上次同步记录的 API 日期在此天数内视为可信,超出后降级回 today。
24+
# 3 天覆盖普通周末和含周一假期的三天长周末。
25+
_STALE_GRACE_DAYS = 3
2326

2427

2528
def _parse_date(date_str: Optional[str]) -> Optional[date]:
@@ -82,15 +85,16 @@ def get_products_overview(
8285
local_date = read_local_timestamp_date(data_root, product)
8386
last = last_results.get(product, {})
8487
last_status = last.get("status", "")
85-
last_reason = last.get("reason_code", "")
86-
# 门控确认已追平(up_to_date)且本地有数据 → 直接视为 0 天落后
87-
# 其他情况用上次记录的 API 日期作为参考;
88-
# 旧安装无 date_time 字段时 _parse_date 返回 None,降级回 today(等价修复前行为)
89-
if last_reason == "up_to_date" and local_date is not None:
90-
behind = 0
91-
else:
92-
ref_date = _parse_date(last.get("date_time", "")) or today
93-
behind = _days_behind(local_date, ref_date)
88+
# 用缓存的 API 日期作为参考,避免周末/假日误报落后;
89+
# 缓存超过宽限期或无缓存时降级回 today,提示可能有新数据
90+
cached_api_date = _parse_date(last.get("date_time", ""))
91+
cache_fresh = (
92+
cached_api_date is not None
93+
and today is not None
94+
and (today - cached_api_date).days <= _STALE_GRACE_DAYS
95+
)
96+
ref_date = cached_api_date if cache_fresh else today
97+
behind = _days_behind(local_date, ref_date)
9498
color = _status_color(behind, last_status)
9599
overview.append({
96100
"name": product,

tests/test_data_query.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,33 @@ def test_overview_up_to_date_reason_shows_green(self):
214214
self.assertEqual(overview[0]["days_behind"], 0)
215215
self.assertEqual(overview[0]["status_color"], "green")
216216

217+
def test_overview_stale_cache_degrades_to_today(self):
218+
"""缓存的 API 日期超过宽限期后,降级回 today 比较。
219+
220+
回归测试:防止长期未同步的产品永远显示绿色。
221+
"""
222+
self._write_timestamp("stock-trading-data", "2026-03-10")
223+
self._write_report("run_report_20260310_update.json", [
224+
{"product": "stock-trading-data", "status": "ok", "reason_code": "ok",
225+
"error": "", "date_time": "2026-03-10"},
226+
])
227+
228+
import unittest.mock
229+
with unittest.mock.patch(
230+
"quantclass_sync_internal.data_query.report_dir_path",
231+
return_value=self.log_dir,
232+
):
233+
# 4 天后查看(超出 3 天宽限期),应降级回 today
234+
overview = get_products_overview(
235+
self.data_root,
236+
["stock-trading-data"],
237+
today=date(2026, 3, 14),
238+
)
239+
240+
# today - local = 4 天,应显示红色
241+
self.assertEqual(overview[0]["days_behind"], 4)
242+
self.assertEqual(overview[0]["status_color"], "red")
243+
217244
def test_overview_with_error_product(self):
218245
"""产品上次失败时应为红色。"""
219246
self._write_timestamp("stock-fin-data-xbx", "2026-03-13")

0 commit comments

Comments
 (0)