From 14a42aac7b33587f4829da18b68d1f1dae29f9bf Mon Sep 17 00:00:00 2001 From: ymq Date: Sat, 15 Aug 2026 01:09:05 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20SELECT-only=20=E4=BA=8B=E5=8A=A1?= =?UTF-8?q?=E6=98=BE=E5=BC=8F=20COMMIT=EF=BC=8C=E4=BF=AE=E5=A4=8D=20MDL=20?= =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E9=94=81=E6=B3=84=E6=BC=8F=E9=98=BB?= =?UTF-8?q?=E5=A1=9E=20DDL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit failed poller / handle_failed_task 的 SELECT-only 事务未提交,连接回池后仍持有元数据锁, 导致 ALTER TABLE ADD COLUMN 卡死并阻塞整表。改为 SELECT 后显式 COMMIT 释放锁。 --- pipeline_service/agent_loop.py | 5 +++++ pipeline_service/init.py | 3 +++ 2 files changed, 8 insertions(+) diff --git a/pipeline_service/agent_loop.py b/pipeline_service/agent_loop.py index 1076e39..aef088d 100644 --- a/pipeline_service/agent_loop.py +++ b/pipeline_service/agent_loop.py @@ -941,6 +941,8 @@ async def handle_failed_task(task_id: str, project_id: str) -> dict: "WHERE id=${tid}$ AND state='failed'", {"tid": task_id}) if not recs: + # 释放 SELECT 的元数据锁,防止连接回池后阻塞 DDL + await sor.sqlExe("COMMIT", {}) return {"status": "idle", "task_id": task_id} t = recs[0] title = getattr(t, "title", "") or "" @@ -951,6 +953,9 @@ async def handle_failed_task(task_id: str, project_id: str) -> dict: retry_count = 0 last_error = getattr(t, "last_error", "") or "" + # 释放 SELECT 的元数据锁,避免决策/建问题期间长时间持有 MDL + await sor.sqlExe("COMMIT", {}) + # 已重试 3 次仍未成功 → 报故障 if retry_count >= 3: decision = "fault" diff --git a/pipeline_service/init.py b/pipeline_service/init.py index 9f49193..bc450c3 100644 --- a/pipeline_service/init.py +++ b/pipeline_service/init.py @@ -663,6 +663,9 @@ def load_pipeline_service(): _fd_dispatched.discard(tid) asyncio.ensure_future(_fd_dispatch(tid, pid)) + # SELECT-only 事务必须显式 COMMIT,否则连接回到池后仍持有元数据锁(MDL), + # 会阻塞后续 ALTER TABLE / DDL(sqlor 只在有写入时才自动提交)。 + await sor.sqlExe("COMMIT", {}) except Exception as e: debug(f"failed_poller error: {e}") await asyncio.sleep(60)