From aaaac95b53d78b2076d70b49770b1227c0020dfa Mon Sep 17 00:00:00 2001 From: chenjw28 <792430652@qq.com> Date: Sat, 26 Sep 2026 23:17:33 +0800 Subject: [PATCH] =?UTF-8?q?fix(init=5Fdb):=20await=20=E4=BC=98=E5=85=88?= =?UTF-8?q?=E7=BA=A7=E6=BC=8F=E6=8B=AC=E5=8F=B7=E2=80=94=E2=80=94=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E8=BF=81=E7=A7=BB=E8=87=AA=E8=AF=9E=E7=94=9F=E8=B5=B7?= =?UTF-8?q?=E4=BB=8E=E6=9C=AA=E6=89=A7=E8=A1=8C=E6=88=90=E5=8A=9F=EF=BC=88?= =?UTF-8?q?=E4=BA=8B=E6=95=85=E6=A0=B9=E5=9B=A0=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit has_alembic = await conn.execute(...).scalar() 因 await 优先级低于 属性访问,实际解析为 await (conn.execute(...).scalar())——在协程对象 上调 .scalar() 必抛 AttributeError('coroutine' object has no attribute 'scalar')。启动迁移每次容器启动都在第一行炸掉,再被 except 吞成一行 日志(4a5dc61 已改为 logger.exception)。两行均改为 (await conn.execute(...)).scalar()。 已于生产库实测:主库路径(has_alembic=True→upgrade no-op)与临时 历史库路径(stamp+upgrade)全部跑通,临时库已删除。 至此 2026-09-26 事故根因链闭合:启动迁移从未生效 → prod schema 长期 落后于模型 → 新镜像上线即上传 500(缺 product_id)。 Co-Authored-By: Claude Code --- src/shared/database/init_db.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/shared/database/init_db.py b/src/shared/database/init_db.py index c0c9a4c..b81210c 100644 --- a/src/shared/database/init_db.py +++ b/src/shared/database/init_db.py @@ -35,11 +35,15 @@ async def _run_alembic_migrations() -> None: - 既有但无 alembic_version(历史 DB):先 stamp head 基线,再 upgrade(no-op) """ async with db_manager.engine.begin() as conn: - has_alembic = await conn.execute(text("SELECT to_regclass('public.alembic_version')")).scalar() + # 注意括号:await 优先级低于属性访问,await conn.execute(...).scalar() + # 实际是 await (conn.execute(...).scalar())——会在协程对象上调 .scalar() + # 直接 AttributeError。必须 (await conn.execute(...)).scalar()。 + # 曾因漏括号让启动迁移自诞生起一次都没跑通过(2026-09-26 事故根因)。 + has_alembic = (await conn.execute(text("SELECT to_regclass('public.alembic_version')"))).scalar() if not has_alembic: - table_count = await conn.execute( + table_count = (await conn.execute( text("SELECT count(*) FROM information_schema.tables WHERE table_schema='public' AND table_name <> 'alembic_version'") - ).scalar() + )).scalar() if table_count and table_count > 0: logger.info("检测到既有 DB 未纳入 alembic 管理,自动 stamp head 作为基线") await asyncio.to_thread(_alembic_stamp_head)