- 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
134 lines
3.8 KiB
Python
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()
|