Files
Profeto/src/data/sources.py
T
shangfangjian 494751bbb0 feat: 数据采集健壮性改进
- 新增 src/core/retry.py: 指数退避 + 抖动的重试装饰器
- bzzoiro: 改进重试逻辑
  - 429/5xx/网络错误均触发指数退避重试
  - 4xx 直接抛(不重试)
- understat: 新增重试(原无重试)
- injuries: 新增重试 + 文件缓存 7 天过期
- sources.py: 延迟导入修复循环导入
2026-09-09 21:47:56 +08:00

65 lines
1.6 KiB
Python

"""数据源协议 + 注册表。
定义 DataSource 契约,并提供全局注册表供路由层分发。
每个比赛数据源实现该协议,注册后即可通过统一入口调度。
注: injuries 是球员级独立领域(写 Injury 表),不遵循此协议。
"""
from __future__ import annotations
from typing import Protocol
from src.db.base import AsyncSession
class DataSource(Protocol):
"""比赛数据源契约:抓取 → 规范化 → 入库。"""
@property
def name(self) -> str:
"""数据源标识名(用于路由/日志)。"""
...
async def ingest(self, db: AsyncSession, **kwargs) -> dict:
"""执行完整采集流程,返回统计。"""
...
# ── 注册表 ──
_SOURCES: dict[str, DataSource] = {}
def register(source: DataSource) -> DataSource:
"""装饰器:将数据源注册到全局注册表。"""
_SOURCES[source.name] = source
return source
def get_source(name: str) -> DataSource:
"""按名获取数据源。"""
if not _SOURCES:
_load_sources()
if name not in _SOURCES:
raise ValueError(f"未知数据源: {name}")
return _SOURCES[name]
def list_sources() -> list[str]:
"""列出所有已注册数据源名。"""
if not _SOURCES:
_load_sources()
return list(_SOURCES.keys())
def _load_sources() -> None:
"""延迟导入数据源触发 @register(避免循环导入)。"""
from src.data.bzzoiro import BzzoiroSource # noqa: F811
from src.data.understat import UnderstatSource # noqa: F811
# 保持向后兼容:模块加载时尝试加载(但不再强制)
try:
_load_sources()
except Exception:
pass