"""健康检查接口。 路由写 `def`(同步)而非 `async def`:FastAPI 会把同步路由放入线程池执行, 因此这里的数据库与 Redis 探测不会阻塞事件循环。 """ import logging from typing import Any from fastapi import APIRouter from sqlalchemy import text from app.core.db import get_session_factory from app.core.redis_client import get_redis from app.core.response import ApiResponse, ok logger = logging.getLogger(__name__) router = APIRouter(tags=["系统"]) def _check_db() -> bool: """探测数据库连通性。失败只记日志并返回 False,不抛出。""" try: factory = get_session_factory() with factory() as session: session.execute(text("SELECT 1")) return True except Exception: logger.warning("数据库健康检查未通过", exc_info=True) return False def _check_redis() -> bool: """探测 Redis 连通性。失败只记日志并返回 False,不抛出。""" try: return bool(get_redis().ping()) except Exception: logger.warning("Redis 健康检查未通过", exc_info=True) return False @router.get("/health", response_model=ApiResponse[dict[str, Any]], summary="健康检查") def health() -> ApiResponse[dict[str, Any]]: """探活接口:上报应用、数据库、Redis 三项状态。 即使依赖不可用,本接口本身仍返回 200 并在 data 中标记 false —— 这样运维能区分「服务没起来」与「服务起来了但依赖挂了」两种情况。 注意:生产部署应限制本接口仅内网可达,避免对外暴露依赖拓扑。 """ return ok({"app": True, "db": _check_db(), "redis": _check_redis()})