fix(trading-day): 「未知」结论也按 TTL 缓存, 不再每拍重打探测

is_trading_day 的缓存命中条件带了 `_CACHE.verdict is not None`, 于是探测链
全部返回 None 时缓存永远读不回来, _TTL_UNKNOWN_S(300s) 形同虚设。

消费方 quote_service._holiday_gate 与 minute_refresh._gate_reason 在轮询循环里
每拍都调 is_trading_day: 未配 fuyao 且 tickflow 实时不可用/网络失败时, 每拍都会
重跑一遍探测链 (含一次 quotes.get 网络请求), 白白消耗限流额度并刷日志。

_CACHE.day 只在探测写回时设置, 「当天已探过」用它判定即可, 去掉多余的
verdict 判空条件。已有的 test_unknown_verdict_retries_after_short_ttl 仍然通过
(TTL 过期后照常重探)。
This commit is contained in:
kevin9327
2026-09-10 19:36:30 +09:00
parent bb94cd7b29
commit e956e3a6d7
2 changed files with 25 additions and 1 deletions
+3 -1
View File
@@ -113,9 +113,11 @@ def is_trading_day(now: datetime | None = None) -> bool | None:
return False return False
with _CACHE_LOCK: with _CACHE_LOCK:
# 「未知」(None) 也是一个结论, 同样按 TTL 缓存 —— 它正是 _TTL_UNKNOWN_S 要
# 挡住的场景 (未配 fuyao 且 tickflow 不可用时, 轮询每拍都会重打一次探测)。
# _CACHE.day 只在探测写回时设置, 因此「当天已探过」用它判定即可。
if ( if (
_CACHE.day == now.date() _CACHE.day == now.date()
and _CACHE.verdict is not None
and (time.monotonic() - _CACHE.probed_at) < _ttl_of(_CACHE.verdict) and (time.monotonic() - _CACHE.probed_at) < _ttl_of(_CACHE.verdict)
): ):
return _CACHE.verdict return _CACHE.verdict
+22
View File
@@ -254,3 +254,25 @@ def test_fuyao_provider_trading_days_conversion(monkeypatch):
monkeypatch.setattr(fp, "get_api_key", lambda: "test-key") monkeypatch.setattr(fp, "get_api_key", lambda: "test-key")
days = FuyaoProvider().trading_days() days = FuyaoProvider().trading_days()
assert days == {date(2026, 9, 4), date(2026, 9, 7)} assert days == {date(2026, 9, 4), date(2026, 9, 7)}
def test_unknown_verdict_is_cached_within_short_ttl(monkeypatch):
"""未知结论也要按 _TTL_UNKNOWN_S 缓存: 轮询每拍重探会重复打 tickflow 请求。"""
monday = datetime(2026, 9, 7, 10, 0, tzinfo=CN)
calls = {"fuyao": 0, "tickflow": 0}
def _fuyao(now):
calls["fuyao"] += 1
return None
def _tickflow(now):
calls["tickflow"] += 1
return None
monkeypatch.setattr(trading_day, "_probe_fuyao", _fuyao)
monkeypatch.setattr(trading_day, "_probe_tickflow", _tickflow)
assert is_trading_day(monday) is None
assert is_trading_day(monday) is None
assert is_trading_day(monday) is None
assert calls == {"fuyao": 1, "tickflow": 1}