fix(portfolio): 桥1m超时降级no_anchor——盘后桥不伺候分钟史不再炸整份IS日报 [vps] [no-doc]
infra 09-28 部署后 §287 probe 定案:盘后桥 1m 查询 >30s 抛 TimeoutError,
经 make_price_fn→_build_leg 穿透 run_day,scheduler 兜底只记日志 → 整份
IS 日报缺失(而非 no_anchor 降级)。修=is_price_source_vps.make_price_fn
捕获 TimeoutError→缓存空 dict:调用方按无分钟数据走宁缺毋假降级链
(decision→no_anchor,arrival→派发 tick 兜底),日线锚(本地 dbbardata)
不受牵连;同 (day,code) 只烧一次 30s 超时后 fail-fast。probe() 不经此层
保持 fail-loud。今晚 20:50 首跑 cd1793c 新决策价口径的前提保障。
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -146,6 +146,10 @@ def make_price_fn():
|
||||
"""PriceFn:minute≠None 走桥分钟缓存;None 走 dbbardata 日 close。
|
||||
|
||||
缓存键=(day, code)——只按 day 键会首票之后全票静默拿 None 锚(终审核修)。
|
||||
桥 1m 超时(盘后桥不伺候分钟史,RPC 默认 30s)按无分钟数据降级:缓存空
|
||||
dict → 调用方走 no_anchor/派发 tick 兜底(宁缺毋假),不炸 run_day 整份
|
||||
日报(09-28 infra probe 定案);同 (day,code) 只烧一次超时,空缓存命中
|
||||
fail-fast。probe() 不经此层,保持 fail-loud。
|
||||
"""
|
||||
cache: dict[tuple[str, str], dict[tuple[str, str], float]] = {}
|
||||
|
||||
@@ -156,7 +160,10 @@ def make_price_fn():
|
||||
return bars and bars["close"]
|
||||
key = (day, code)
|
||||
if key not in cache:
|
||||
cache[key] = _minute_closes([code], day)
|
||||
try:
|
||||
cache[key] = _minute_closes([code], day)
|
||||
except TimeoutError:
|
||||
cache[key] = {}
|
||||
return cache[key].get((code, minute))
|
||||
return fn
|
||||
|
||||
|
||||
@@ -32,3 +32,35 @@ def test_minute_rows_to_map_legacy_nested_and_nan():
|
||||
"bad": None}}
|
||||
m = minute_rows_to_map(legacy, "600276.SH")
|
||||
assert m == {("600276.SH", "10:00"): 44.8}
|
||||
|
||||
|
||||
def test_make_price_fn_minute_timeout_degrades(monkeypatch):
|
||||
"""桥 1m 超时(盘后桥不伺候分钟史,RPC 默认 30s)→ 按无分钟数据降级返
|
||||
None(宁缺毋假 no_anchor/派发 tick 兜底),不炸 run_day 整份日报;
|
||||
同 (day,code) 只烧一次超时(空缓存命中 fail-fast)。09-28 infra probe 定案。"""
|
||||
import scripts.pipeline.is_price_source_vps as psrc
|
||||
calls = []
|
||||
|
||||
def boom(symbols, day):
|
||||
calls.append((symbols, day))
|
||||
raise TimeoutError("rpc timeout")
|
||||
|
||||
monkeypatch.setattr(psrc, "_minute_closes", boom)
|
||||
fn = psrc.make_price_fn()
|
||||
assert fn("600276.SH", "2026-09-28", "09:31") is None
|
||||
assert fn("600276.SH", "2026-09-28", "09:32") is None # 缓存命中不再烧
|
||||
assert calls == [(["600276.SH"], "2026-09-28")]
|
||||
|
||||
|
||||
def test_make_price_fn_daily_path_untouched_by_minute_timeout(monkeypatch):
|
||||
"""分钟腿降级不影响日线锚(close/prev_close 走本地 dbbardata,日报仍有
|
||||
close 锚——两条腿互不牵连)。"""
|
||||
import scripts.pipeline.is_price_source_vps as psrc
|
||||
|
||||
def boom(symbols, day):
|
||||
raise TimeoutError("rpc timeout")
|
||||
|
||||
monkeypatch.setattr(psrc, "_minute_closes", boom)
|
||||
monkeypatch.setattr(psrc, "_daily_bars", lambda sym, day: {"close": 44.9})
|
||||
fn = psrc.make_price_fn()
|
||||
assert fn("600276.SH", "2026-09-28", None) == 44.9
|
||||
|
||||
Reference in New Issue
Block a user