81 lines
3.0 KiB
Python
81 lines
3.0 KiB
Python
"""main.py —— 生信服务应用入口(uvicorn 入口,明文白名单文件)。
|
||
|
||
- 独立部署树 bioflow_service/(FR-BIO-028:独立进程 8098 + 独立 SQLite)。
|
||
- lifespan:init_db(幂等迁移)→ init_context(kernel/catalog/planner/runner)
|
||
→ recover(服务重启恢复 in-flight 续跑,FR-BIO-031)→ shutdown 清理。
|
||
- 端点:health(/api/bioflow/health,前端探活 FR-BIO-025)。
|
||
- 不依赖 BFF/生产服务(8090/8091 等绝不探测/连接)。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import logging
|
||
from contextlib import asynccontextmanager
|
||
|
||
from fastapi import FastAPI
|
||
from fastapi.middleware.cors import CORSMiddleware
|
||
|
||
from .config import get_settings
|
||
from .context import context, init_context, shutdown_context
|
||
from .db import close_db, init_db
|
||
from .routers import bioarchives, bioflow, biojobs
|
||
|
||
logging.basicConfig(level=logging.INFO)
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
def create_app() -> FastAPI:
|
||
settings = get_settings()
|
||
app = FastAPI(title=settings.app_name, version=settings.version)
|
||
|
||
app.add_middleware(
|
||
CORSMiddleware,
|
||
allow_origins=["*"], # 生信服务直连形态(FR-BIO-027);BFF 反代为同源
|
||
allow_credentials=False,
|
||
allow_methods=["*"],
|
||
allow_headers=["*"],
|
||
)
|
||
|
||
@asynccontextmanager
|
||
async def _lifespan(_app: FastAPI):
|
||
# 测试注入:context.db 已由测试预置(build_context 注入的临时库),
|
||
# 跳过启动初始化(不替换全局 db、不加载真实映射表、不 recover)。
|
||
# 注意经模块属性动态读取(monkeypatch 替换的是 context 模块的全局)。
|
||
from . import context as context_mod
|
||
|
||
injected = context_mod.context.db is not None
|
||
if not injected:
|
||
try:
|
||
await init_db()
|
||
except Exception:
|
||
# SQLite 初始化失败不阻断服务启动(health 报 db 降级;端点返回 INTERNAL)
|
||
logger.exception("main: 数据库初始化失败(health 将报 db 降级)")
|
||
try:
|
||
await init_context()
|
||
except Exception:
|
||
logger.exception("main: context 初始化失败(kernel 映射表缺失时 docker 执行不可用)")
|
||
try:
|
||
if context_mod.context.runner is not None:
|
||
recovered = await context_mod.context.runner.recover()
|
||
if recovered:
|
||
logger.info("main: 重启恢复 %d 个 in-flight 任务续跑", len(recovered))
|
||
except Exception:
|
||
logger.exception("main: 重启恢复扫描失败(任务不重跑,等待后续操作)")
|
||
try:
|
||
yield
|
||
finally:
|
||
await shutdown_context()
|
||
try:
|
||
await close_db()
|
||
except Exception:
|
||
pass
|
||
|
||
app.router.lifespan_context = _lifespan
|
||
|
||
app.include_router(bioflow.router)
|
||
app.include_router(biojobs.router)
|
||
app.include_router(bioarchives.router)
|
||
return app
|
||
|
||
|
||
app = create_app()
|