fix: telemetry single persistent connection + lock (kill concurrent write lock)

This commit is contained in:
2026-07-16 08:47:23 -04:00
parent 766592d855
commit 065c8ae1b9
3 changed files with 85 additions and 27 deletions
+47
View File
@@ -146,3 +146,50 @@ async def test_concurrent_writes_no_lock_error(recorder, db_path):
count = conn.execute("SELECT COUNT(*) FROM llm_calls").fetchone()[0]
conn.close()
assert count == 16
def test_high_concurrency_writes_zero_loss(recorder, db_path):
"""64 路线程并发直压 _write 应零丢失——复现生产 concurrency 下 database is locked 丢失。
直接压同步 _write(不经 to_thread 排队),最大化并发连接数以逼出锁竞争;
单连接 + threading.Lock 串行化模式下应全部落库、零丢失(对齐 HarnessLog)。
"""
import concurrent.futures
n = 64
kwargs_list = [_make_call_kwargs() for _ in range(n)]
with concurrent.futures.ThreadPoolExecutor(max_workers=n) as executor:
list(executor.map(lambda kw: recorder._write(**kw), kwargs_list))
conn = sqlite3.connect(str(db_path))
count = conn.execute("SELECT COUNT(*) FROM llm_calls").fetchone()[0]
conn.close()
assert count == n, f"并发写丢失 {n - count} 条(database is locked 降级丢弃): 落库 {count}/{n}"
def test_uses_single_persistent_connection(db_path, monkeypatch):
"""对齐 HarnessLog:单持久连接(构造时建一次),写入复用而非每次新建。
每次写新建连接是并发锁竞争根源(多连接争 SQLite 写锁,撑爆 busy_timeout);
单连接 + 进程内 Lock 串行化把并发控制拉到进程内,消除 SQLite 层锁竞争。
"""
connect_calls = {"n": 0}
real_connect = sqlite3.connect
def _counting_connect(*args, **kwargs):
connect_calls["n"] += 1
return real_connect(*args, **kwargs)
monkeypatch.setattr(sqlite3, "connect", _counting_connect)
recorder = SQLiteTelemetryRecorder(db_path=db_path)
after_init = connect_calls["n"]
for _ in range(10):
recorder._write(**_make_call_kwargs())
after_writes = connect_calls["n"]
assert after_init >= 1, "构造时应建立持久连接(对齐 HarnessLog)"
assert after_writes == after_init, (
f"写入期间新建了 {after_writes - after_init} 个连接(应复用单持久连接,"
"每次新连接是并发锁竞争根源)"
)