feature:基本框架
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
"""四库统一注册表:异步生命周期编排。
|
||||
|
||||
启动:逐库 init,失败按指数退避重试;DB_STRICT_STARTUP=true 时重试耗尽直接抛错阻止启动。
|
||||
关闭:逆序 dispose。健康:check_ready_detail 返回带耗时明细,供 /health 与监控面板使用。
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
|
||||
from . import milvus, mysql, neo4j, redis
|
||||
from config.settings import settings
|
||||
|
||||
logger = logging.getLogger("config.database")
|
||||
|
||||
# 关闭顺序与设计一致:mysql → redis → neo4j → milvus
|
||||
_DB_MODULES = (mysql, redis, neo4j, milvus)
|
||||
|
||||
|
||||
def _name(m) -> str:
|
||||
return m.__name__.rsplit(".", 1)[-1]
|
||||
|
||||
|
||||
async def _init_with_retry(m, strict: bool) -> bool:
|
||||
name = _name(m)
|
||||
retries = settings.db.conn_retries
|
||||
for attempt in range(retries):
|
||||
try:
|
||||
await m.init_db()
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"[%s] init failed (attempt %d/%d): %s: %s",
|
||||
name, attempt + 1, retries, type(e).__name__, e,
|
||||
)
|
||||
if attempt < retries - 1:
|
||||
await asyncio.sleep(settings.db.retry_backoff_sec * (2**attempt))
|
||||
if strict:
|
||||
raise RuntimeError(f"[{name}] 初始化失败({retries} 次尝试后)")
|
||||
return False
|
||||
|
||||
|
||||
async def init_db() -> None:
|
||||
"""手动预热(应用启动不自动调用,会话懒创建):asyncio.run(database.init_db())"""
|
||||
for m in _DB_MODULES:
|
||||
await _init_with_retry(m, settings.db.strict_startup)
|
||||
|
||||
|
||||
async def dispose() -> None:
|
||||
for m in _DB_MODULES:
|
||||
try:
|
||||
await m.dispose()
|
||||
except Exception as e:
|
||||
logger.warning("[%s] dispose failed: %s: %s", _name(m), type(e).__name__, e)
|
||||
|
||||
|
||||
async def check_ready_detail() -> dict[str, dict]:
|
||||
"""含耗时明细:{db: {status, ms}}。任一失败不影响其它库探测。"""
|
||||
out: dict[str, dict] = {}
|
||||
for m in _DB_MODULES:
|
||||
name = _name(m)
|
||||
t0 = time.perf_counter()
|
||||
try:
|
||||
await m.check_health()
|
||||
status = "ok"
|
||||
except Exception as e:
|
||||
status = f"down: {type(e).__name__}"
|
||||
out[name] = {"status": status, "ms": round((time.perf_counter() - t0) * 1000, 1)}
|
||||
return out
|
||||
|
||||
|
||||
async def check_ready() -> dict[str, str]:
|
||||
"""兼容旧契约:{db: status_str}。"""
|
||||
return {k: v["status"] for k, v in (await check_ready_detail()).items()}
|
||||
Reference in New Issue
Block a user