Files
34047007@qq.com 86126ea16f checkpoint: 架构治理四件套——统一 async / 测试真 PG / Redis 降级可选 / DPB 扶正
- A1 业务层统一 async:gencode 表内省改 run_sync 异步(不再阻塞事件循环)、
  check_db 改 async_engine、dict_util 启动预热异步载入;psycopg 降为
  APScheduler SQLAlchemyJobStore 专用同步孤岛(注释标注)
- A2 测试真 PG 化:conftest 弃 SQLite + mock Redis,改连真实 PG16(dpb_test)+
  Redis(number_gen advisory lock 路径真被测);新增 docker/test-compose.yaml
  测试依赖栈(postgres:16:5433 + redis:7:6380);run_ci 前置探测 + 容器兜底,
  pytest -m pg 10 套正式 tc 全过(真实 PG16 + Redis)
- B1 Redis 启动不强依赖:redis_connect 失败降级启动,缓存类回源 DB、存储类
  (会话/AI 配置/调度)经 require_redis 守卫返回 503;真机 3 阶段降级测试
  PASS=11 FAIL=0(独立 Redis 6390 + 后端 8091,不动共享 dev 服务)
- C 扶正 DPB:后端横幅/日志(dpb.log)/README/pyproject/ai_factory agent 名、
  前端 package.json/署名注释/链接文案/deploy.sh/docker 注释全部去 fastapiadmin;
  grep backend/app + frontend/web/src 零残留
- 验证:全量回归 pass=72 fail=0
2026-08-07 09:06:19 +08:00

134 lines
3.8 KiB
Python

import os
# 必须在导入 settings(构建配置单例)之前确定运行环境。
# 否则 env_file=ENV_DIR/".env.{os.getenv('ENVIRONMENT')}" 在 import 时求值为
# ".env.None"(环境变量尚未设置),导致 .env.dev 等环境文件不被加载,
# dev 下 CAPTCHA_ENABLE 等配置不生效、登录反复 500。
os.environ.setdefault("ENVIRONMENT", "dev")
from typing import Annotated
import typer
import uvicorn
from alembic import command
from alembic.config import Config
from fastapi import FastAPI
from app.common.enums import EnvironmentEnum
from app.config.setting import settings
from app.utils.banner import worship
dpb_cli = typer.Typer()
alembic_cfg = Config("alembic.ini")
def create_app() -> FastAPI:
"""创建 FastAPI 应用实例并完成日志、中间件、路由与静态资源注册。
返回:
- FastAPI: 已配置生命周期的应用对象。
"""
from app.init_app import lifespan, register_docs, register_exceptions, register_frontend, register_middlewares, register_routers, register_static
# 创建FastAPI应用
app = FastAPI(**settings.FASTAPI_CONFIG, lifespan=lifespan)
# 注册异常处理器
register_exceptions(app)
# 注册中间件
register_middlewares(app)
# 注册路由
register_routers(app)
# 注册静态文件
register_static(app)
# 注册API文档(豁免限流)
register_docs(app)
# 注册前端
register_frontend(app)
return app
# typer.Option是非必填;typer.Argument是必填
@dpb_cli.command(
name="run",
help="启动 DPB 桃育种系统服务, 运行 uv run main.py run --env=dev 不加参数默认 dev 环境",
)
def run(
env: Annotated[EnvironmentEnum, typer.Option("--env", help="运行环境 (dev, prod)")] = EnvironmentEnum.DEV,
) -> None:
"""按指定环境加载配置并启动 Uvicorn(开发环境开启 reload)。
参数:
- env (EnvironmentEnum): 运行环境,对应 `--env`。
返回:
- None
"""
# 设置环境变量(必须在 import settings 之前,确保加载正确环境)
os.environ["ENVIRONMENT"] = env.value
typer.secho(
message=f"{worship()}",
fg=typer.colors.GREEN,
)
# 启动uvicorn服务
uvicorn.run(
app="main:create_app",
host=settings.SERVER_HOST,
port=settings.SERVER_PORT,
reload=env.value == EnvironmentEnum.DEV.value,
factory=True,
log_config=None,
timeout_graceful_shutdown=5,
)
@dpb_cli.command(
name="revision",
help="生成新的 Alembic 迁移脚本, 运行 python main.py revision --env=dev",
)
def revision(
env: Annotated[EnvironmentEnum, typer.Option("--env", help="运行环境 (dev, prod)")] = EnvironmentEnum.DEV,
) -> None:
"""使用 Alembic 自动生成迁移脚本(autogenerate)。
参数:
- env (EnvironmentEnum): 运行环境,用于加载对应数据库模型元数据。
返回:
- None
"""
os.environ["ENVIRONMENT"] = env.value
from app.config.setting import get_settings
get_settings.cache_clear()
command.revision(alembic_cfg, autogenerate=True, message="迁移脚本")
typer.echo("迁移脚本已生成")
@dpb_cli.command(
name="upgrade",
help="应用最新的 Alembic 迁移, 运行 python main.py upgrade --env=dev",
)
def upgrade(
env: Annotated[EnvironmentEnum, typer.Option("--env", help="运行环境 (dev, prod)")] = EnvironmentEnum.DEV,
) -> None:
"""将数据库升级到 Alembic 最新版本(head)。
参数:
- env (EnvironmentEnum): 运行环境。
返回:
- None
"""
os.environ["ENVIRONMENT"] = env.value
from app.config.setting import get_settings
get_settings.cache_clear()
command.upgrade(alembic_cfg, "head")
typer.echo("所有迁移已应用。")
if __name__ == "__main__":
dpb_cli()