From 0f2ec7987c781765fca3eb5f5706a05d500fbe0a Mon Sep 17 00:00:00 2001 From: OG T Date: Wed, 15 Apr 2026 15:18:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(db):=20=E6=94=B9=E7=94=A8=20inspect=20?= =?UTF-8?q?=E8=B7=B3=E9=81=8E=E7=8F=BE=E6=9C=89=20table=EF=BC=8C=E6=A0=B9?= =?UTF-8?q?=E6=B2=BB=20CrashLoopBackOff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit checkfirst=True 只跳過 CREATE TABLE,SQLAlchemy 2.0 仍對 __table_args__ Index 物件發出獨立 CREATE INDEX → duplicate error。 改法:先 inspect 取得現有 tables,只對不存在的 table 呼叫 table.create(),index 永遠只隨新 table 建立,不再 duplicate。 Co-Authored-By: Claude Sonnet 4.6 --- apps/api/src/db/base.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/api/src/db/base.py b/apps/api/src/db/base.py index e17a68ab..12082876 100644 --- a/apps/api/src/db/base.py +++ b/apps/api/src/db/base.py @@ -144,9 +144,19 @@ async def init_db() -> None: """ engine = get_engine() async with engine.begin() as conn: - # checkfirst=True: 存在的 table/index 直接跳過,避免 rolling update 重啟時 - # "relation already exists" CrashLoopBackOff(2026-04-15 Claude Sonnet 4.6 Phase 3 修復) - await conn.run_sync(lambda c: Base.metadata.create_all(c, checkfirst=True)) + # SQLAlchemy 2.0 問題:create_all(checkfirst=True) 跳過 CREATE TABLE, + # 但仍對 __table_args__ Index 物件發出獨立 CREATE INDEX → CrashLoopBackOff + # 修法:先 inspect 取得現有 tables,只對不存在的 table 呼叫 table.create() + # 這樣 index 只隨新 table 一起建立,永遠不會 duplicate + # 2026-04-15 Claude Sonnet 4.6(亞太)Phase 3 修復 + def _create_missing_tables(sync_conn): + from sqlalchemy import inspect as sa_inspect + existing = set(sa_inspect(sync_conn).get_table_names()) + for table in Base.metadata.sorted_tables: + if table.name not in existing: + table.create(sync_conn) + + await conn.run_sync(_create_missing_tables) # 2026-04-02 Claude Code: 確保 risklevel enum 包含 'high' 值 # Phase 23 新增,避免舊 DB 缺少此值導致 InvalidTextRepresentation