fix: 数据库与数据管线 6 个 P1 + 5 个 P2 审查问题修复
P1-1 [context_builder] build_context 共享 session,切片函数传 db 参数,
回测 20 场并发连接需求从 100+ 降至每场 1 个
P1-2 [bzzoiro] 预加载改为按 raw_events 日期范围 ±30 天按需加载
P1-3 [understat] 批量查询球队 + 比赛,从 1140 次往返降到 3 次
P1-4 [injuries] 批量幂等检查 + 分批 flush,IntegrityError 逐条回退
P1-5 [predict] 删除 threading.Lock,dict 操作原子无需同步锁
P1-6 [models] 添加 (match_id, provider, model) 唯一约束 + 迁移
P2-1 [unit_of_work] get_uow 返回类型改为 AsyncIterator[AsyncSession]
P2-2 [normalize] _parse_date 失败时记录 warning 避免静默丢数据
P2-3 [repositories] find_by_teams_and_date 改用 match_date_date 等值匹配
P2-4 [migration] 幽灵列 cutoff_at 已在 0006 迁移删除(已有)
P2-5 [migration] injuries 约束命名对齐 ORM,UniqueConstraint → 唯一索引
This commit is contained in:
+11
-9
@@ -23,8 +23,9 @@ _PROMPT_DIR = Path(__file__).resolve().parent / "prompts"
|
||||
|
||||
# ── LLM 响应缓存(match+provider+model+version → 结果) ──
|
||||
_CACHE_TTL_SEC = 300 # 5 分钟
|
||||
# P1-5: 缓存仅在 asyncio 协程内同步访问(dict 操作 GIL 原子),无需 threading.Lock。
|
||||
# 删除 _cache_lock,避免同步锁阻塞事件循环;dict 的 get/set 在 CPython 下原子。
|
||||
_cache: dict[str, tuple[float, PredictResult]] = {}
|
||||
_cache_lock = Lock()
|
||||
|
||||
|
||||
def _cache_key(match_id: int, provider: str, model: str, version: str, tpl_hash: str) -> str:
|
||||
@@ -38,20 +39,21 @@ def _cache_key(match_id: int, provider: str, model: str, version: str, tpl_hash:
|
||||
|
||||
|
||||
def _get_cached(match_id: int, provider: str, model: str, version: str, tpl_hash: str) -> PredictResult | None:
|
||||
# P1-5: 无锁访问。dict get/del 在 CPython GIL 下原子,且无 await 穿插。
|
||||
key = _cache_key(match_id, provider, model, version, tpl_hash)
|
||||
with _cache_lock:
|
||||
if key in _cache:
|
||||
ts, result = _cache[key]
|
||||
if time.time() - ts < _CACHE_TTL_SEC:
|
||||
return result
|
||||
del _cache[key]
|
||||
entry = _cache.get(key)
|
||||
if entry is not None:
|
||||
ts, result = entry
|
||||
if time.time() - ts < _CACHE_TTL_SEC:
|
||||
return result
|
||||
_cache.pop(key, None)
|
||||
return None
|
||||
|
||||
|
||||
def _set_cached(match_id: int, provider: str, model: str, version: str, tpl_hash: str, result: PredictResult) -> None:
|
||||
# P1-5: 无锁写入。同上,dict set 原子。
|
||||
key = _cache_key(match_id, provider, model, version, tpl_hash)
|
||||
with _cache_lock:
|
||||
_cache[key] = (time.time(), result)
|
||||
_cache[key] = (time.time(), result)
|
||||
|
||||
|
||||
def clear_prompt_cache() -> None:
|
||||
|
||||
Reference in New Issue
Block a user