feat(db): 同步栈读写并发(_q 去锁)+ core.db 并发/跨loop 修复

auth_system._q:单语句读不再持 _DB_LOCK —— WAL 下每连接读一致性快照,
读写互不阻塞;旧实现把全部读也串行化且被写挡住。写事务(_x 与 24 个
with _DB_LOCK 块,经扫描均为写事务)仍全程串行,无写-写竞争。

core.db 并发修复(由测试暴露的真实缺陷):
- WAL 切换竞态:并发连接同时执行 PRAGMA journal_mode=WAL 争排他锁
  → 专用锁内串行切换 + 二次复查(busy_timeout 前置)
- 跨事件循环锁:模块级 asyncio.Lock 绑定首个 loop,多 loop 场景报
  "bound to a different event loop" → 锁按 loop 隔离

测试:25/25 通过(新增「读不被写锁阻塞」红转绿、读+同步写者并发 WAL、
异步并发读);
lint: ruff All checks passed;pyright 0 errors。
验收:冒烟 10/10、奇偶校验 2/2、uvicorn 真实启动 Flask 兜底+FastAPI 双通。
This commit is contained in:
snowy-yang committed 2026-09-26 01:03:18 +08:00
1 parent 52ed8b54fb
commit c77ef40fd5
4 files changed
+141 -16

No files matched your search

+11 -6
View File
@@ -60,12 +60,17 @@ def get_conn() -> sqlite3.Connection:
def _q(sql: str, params: tuple = ()) -> list[sqlite3.Row]:
with _DB_LOCK:
conn = get_conn()
try:
return conn.execute(sql, params).fetchall()
finally:
conn.close()
"""单语句读:**不持锁**。
WAL 模式下每个连接读到一致性快照,读与写互不阻塞;旧实现对读也加 _DB_LOCK,
等于把全部读串行化并被写挡住。此处仅放开单语句读——写事务(_x 与各
`with _DB_LOCK` 块)仍全程串行,故不引入写-写竞争。
"""
conn = get_conn()
try:
return conn.execute(sql, params).fetchall()
finally:
conn.close()
def _x(sql: str, params: tuple = ()) -> int: