From 3ed2f36b1851488b4ed1720246c2a99d19943ff0 Mon Sep 17 00:00:00 2001 From: snowy-yang <102860110+snowy-yang@users.noreply.github.com> Date: Sat, 26 Sep 2026 14:38:05 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=90=AF=E5=8A=A8=E6=97=B6=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E7=AB=99=E7=82=B9=E5=BA=93=E8=A1=A8=E7=BB=93?= =?UTF-8?q?=E6=9E=84=EF=BC=8C=E4=BF=AE=E5=A4=8D=E5=85=A8=E6=96=B0=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E3=80=8C=E6=9C=89=E5=BA=93=E6=97=A0=E8=A1=A8=E3=80=8D?= =?UTF-8?q?=E7=9A=84=E7=BC=BA=E9=99=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为什么:全仓没有任何启动期调用 init_db()——web/app.py 的 lifespan 在 yield 之前不做事(只在关停时清连接池),create_app 也只注入音频密钥。后果是全新部署 (宿主机 data/ 是空目录,compose 用 ./data:/app/data 挂载会盖掉镜像内内容) 启动后,第一次查询只是让 sqlite3 建出一个 **0 表空库**,随后所有涉库端点报 `no such table: users`。 实测证据(SITE_DATA_DIR 指向空目录,起真实 uvicorn): 修复前:POST /auth/login -> 500;site.db 4096 字节 / 0 张表 修复后:POST /auth/login -> 400(用户名或密码错误,即查询真的执行了); site.db 61440 字节 / 9 张表(含 users、settings) 这个故障还极难定位:500 的响应体是「登录失败,请稍后重试」, 把 no such table 整个吞掉了,日志不翻到底看不出来。 改法:在 lifespan 的 yield 之前 `await asyncio.to_thread(auth_system.init_db)`。 init_db 全程 CREATE TABLE IF NOT EXISTS + 幂等迁移,对已有生产库重复执行无副作用 (本次 175 项测试与真实启动冒烟均未触碰 data/,指纹三项一致);初始化失败则让 异常冲出、启动即失败,优于静默带病运行。 --- web/app.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/web/app.py b/web/app.py index bbd732b..ab98481 100644 --- a/web/app.py +++ b/web/app.py @@ -5,12 +5,14 @@ `api_prefix` 用于把整套路由挂到指定前缀下(便于契约测试与反向代理)。 """ +import asyncio from contextlib import asynccontextmanager from pathlib import Path from fastapi import FastAPI from fastapi.staticfiles import StaticFiles +import auth_system from core.config import APP_VERSION from core.security import init_secret_key from web.errors import install_error_handlers @@ -35,7 +37,16 @@ from web.routers import user as user_router @asynccontextmanager async def _lifespan(app: FastAPI): - """应用生命周期:关闭时释放 aiohttp 连接池(含按事件循环隔离的 session)。""" + """应用生命周期:启动确保站点库表结构就绪,关闭时释放 aiohttp 连接池。 + + 启动必须建表。全新部署时宿主机的 data/ 往往是个空目录(compose 用 + `./data:/app/data` 挂载,会盖掉镜像内的任何内容),此时若只等首次查询 + 让 sqlite3 自动建库,得到的是一张 **0 表空库**——随后所有涉库端点报 + `no such table: users`(实测登录端点直接 500,且错误被吞成"请稍后重试", + 极难定位)。init_db 全程 `CREATE TABLE IF NOT EXISTS` + 幂等迁移, + 对已有库重复执行无副作用,故放启动期最稳妥。 + """ + await asyncio.to_thread(auth_system.init_db) yield try: from core import aiohttp_compat, http_client