fix(P0): 修复三处静默失效的阻断缺陷
P0-1 backtest 会话生命周期: - _get_historical_matches 加 selectinload(league/home_team/away_team), 并在 session 内物化为 BacktestCandidate 纯数据快照,避免 session 关闭后访问惰性关系抛 MissingGreenlet - except 收窄并改用 logger.exception 保留堆栈 - 移除未使用的 and_ / League 导入 P0-2 切片函数关系属性 MissingGreenlet: - models.py 为 Match.league/home_team/away_team/stats 声明 lazy=selectin - context_builder 的 _get_form/_get_h2h/_get_home_away 显式 selectinload (修复 form_slice/h2h_slice 恒定失败,被 fail-open 掩盖的问题) - repositories.find_by_teams_and_date 加 selectinload(Match.stats) P0-3 bzzoiro raw 变量泄漏导致血缘错乱: - normalized_matches 改为携带 (nm, raw) 元组,内层循环解包 - source_event_id / source_record_id 现在取到正确 event id - 已有比赛补建 stats 时补齐 source/source_event_id/retrieved_at/available_at - 抽取 _match_key()/_to_date() 统一日期键构造 (P1-6)
This commit is contained in:
@@ -328,9 +328,19 @@ async def _load_match(db, match_id: int) -> Match:
|
||||
|
||||
|
||||
async def _get_form(db, team_id: int, before, *, limit: int = 5) -> list[Match]:
|
||||
"""某队近 N 场(已完赛)。before=None 表示不限制(预测赛前的场景由调用方保证)。"""
|
||||
"""某队近 N 场(已完赛)。before=None 表示不限制(预测赛前的场景由调用方保证)。
|
||||
|
||||
必须预加载 stats / home_team / away_team:切片函数会读取这些关系,
|
||||
而 async session 下惰性加载会抛 MissingGreenlet。
|
||||
(models.py 已声明 lazy="selectin",此处显式声明以固化查询意图。)
|
||||
"""
|
||||
stmt = (
|
||||
select(Match)
|
||||
.options(
|
||||
selectinload(Match.stats),
|
||||
selectinload(Match.home_team),
|
||||
selectinload(Match.away_team),
|
||||
)
|
||||
.where(Match.match_status == "finished")
|
||||
.where(Match.home_goals.is_not(None))
|
||||
.where((Match.home_team_id == team_id) | (Match.away_team_id == team_id))
|
||||
@@ -344,9 +354,13 @@ async def _get_form(db, team_id: int, before, *, limit: int = 5) -> list[Match]:
|
||||
|
||||
|
||||
async def _get_h2h(db, home_id: int, away_id: int, before, *, limit: int = 5) -> list[Match]:
|
||||
"""两队交锋史。"""
|
||||
"""两队交锋史。需预加载 home_team / away_team(切片输出队名)。"""
|
||||
stmt = (
|
||||
select(Match)
|
||||
.options(
|
||||
selectinload(Match.home_team),
|
||||
selectinload(Match.away_team),
|
||||
)
|
||||
.where(Match.match_status == "finished")
|
||||
.where(Match.home_goals.is_not(None))
|
||||
.where(
|
||||
@@ -363,9 +377,17 @@ async def _get_h2h(db, home_id: int, away_id: int, before, *, limit: int = 5) ->
|
||||
|
||||
|
||||
async def _get_home_away(db, team_id: int, side: str, before, *, limit: int = 10) -> list[Match]:
|
||||
"""某队主场/客场近 N 场。side='home' 取主场,'away' 取客场。"""
|
||||
"""某队主场/客场近 N 场。side='home' 取主场,'away' 取客场。
|
||||
|
||||
当前只用标量字段,但统一预加载以免后续扩展时踩坑。
|
||||
"""
|
||||
stmt = (
|
||||
select(Match)
|
||||
.options(
|
||||
selectinload(Match.stats),
|
||||
selectinload(Match.home_team),
|
||||
selectinload(Match.away_team),
|
||||
)
|
||||
.where(Match.match_status == "finished")
|
||||
.where(Match.home_goals.is_not(None))
|
||||
.order_by(Match.match_date.desc())
|
||||
|
||||
Reference in New Issue
Block a user