From 700be2ebae11dd2f80a251d7314f5ddc555e6ca7 Mon Sep 17 00:00:00 2001 From: JustMe Date: Fri, 16 Oct 2026 17:54:30 +0800 Subject: [PATCH] fix(storage): retry a read transaction that fails to begin under load --- .../src/WebDrop.Storage/SqliteChannelStore.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/server/src/WebDrop.Storage/SqliteChannelStore.cs b/server/src/WebDrop.Storage/SqliteChannelStore.cs index 3bb504f..956c70b 100644 --- a/server/src/WebDrop.Storage/SqliteChannelStore.cs +++ b/server/src/WebDrop.Storage/SqliteChannelStore.cs @@ -51,11 +51,21 @@ public sealed class SqliteChannelStore : IResourceStore, IDisposable public T Read(Func action) { - using var conn = Open(); - // 显式事务让一次 Read 内的多条查询看到同一份快照 - // 读事务延迟到首次访问时才取快照,避免并发读预检抢占 SQLite 写锁。 - using var tx = conn.BeginTransaction(deferred: true); - return action(new SqliteTx(conn)); + for (int attempt = 0; ; attempt++) + { + using var conn = Open(); + // 显式事务让一次 Read 内的多条查询看到同一份快照 + // 读事务延迟到首次访问时才取快照,避免并发读预检抢占 SQLite 写锁。 + SqliteTransaction tx; + try { tx = conn.BeginTransaction(deferred: true); } + // 并发压力下偶发 SQLITE_ERROR(CI 的并行追加测试里出现过):丢弃这条连接和池里的闲置连接,换新连接重试 + catch (SqliteException e) when (e.SqliteErrorCode == 1 && attempt < 2) + { + SqliteConnection.ClearPool(conn); + continue; + } + using (tx) return action(new SqliteTx(conn)); + } } public T Write(Func action)