编号:D-03 严重级:medium 工作线:存储、配置、命令行与部署(internal/store、internal/config、cmd/nixmsg 命令、deploy) 来源:审查 P-14 依赖:C-01 (#32)、C-02 (#33)(推送改为先收集结果再发布、推送并发有上限) 被依赖:无
采用审查 P-14 的方案:OpenReader 设 SetMaxIdleConns(16)、SetConnMaxIdleTime(5*time.Minute)、SetMaxOpenConns(64);读连接的 DSN 加 _pragma=query_only(1) 防止误写。
OpenReader
SetMaxIdleConns(16)
SetConnMaxIdleTime(5*time.Minute)
SetMaxOpenConns(64)
_pragma=query_only(1)
前提是不存在"持有查询结果时又发第二个读查询"或"持有查询结果时做可能长时间阻塞的调用"。message.pushReceipts 目前边遍历查询结果边 PublishDown,会长期占住读连接,需要先由 C-02 改成"先收集、再发布";C-01 的推送并发上限也要小于读池上限。
message.pushReceipts
PublishDown
internal/store/db.go。
internal/store/db.go
依赖 C-01、C-02,在它们之后合入。
db.Read.Stats().OpenConnections
以下是本次复审各区审查报告的原文段落。A、M、I、P、S 开头的是原始发现编号(A 管理后台与网页、M 消息核心、I 身份认证群在线、P 传输平台部署、S SDK)。解决方案以本 issue 上方的"结论与统一方案"为准;原文里的方案与之不一致时,按上方执行。
WakePush
store/db.go:95-109
message/push.go:549-560
SetMaxOpenConns
复审基线:main 4059a15(2026-09-30)。编号说明、各工作线的合并顺序、共享文件归属见总览 #7。
4059a15
D-03 已由 C-03 覆盖,本 issue 不另开补丁。 (#29)
feat/fix-message-c01-c03 提交 a4e51ec5cd 中 OpenReader:SetMaxOpenConns(64)、SetMaxIdleConns(16)、SetConnMaxIdleTime(5m),读 DSN _pragma=query_only(1)。
feat/fix-message-c01-c03
a4e51ec5cd
SetConnMaxIdleTime(5m)
测试 internal/store/db_pool_test.go TestReaderPoolCapAndQueryOnly:并发 200 读、OpenConnections<=64、读连接执行写语句报错。
internal/store/db_pool_test.go
TestReaderPoolCapAndQueryOnly
OpenConnections<=64
前提:C-01 每握手连接一个 push worker(不再每个 WakePush 起 goroutine);C-02 回执先收集再发布。读池上限 64 可挡住群发连接风暴。未合入 main。
已合入 origin/main 0c9b459。落地提交 6a65ab8 fix: 按完成时刻分批清理并限制读连接池 (#29)。store 侧见 57c2f70。
0c9b459
6a65ab8
57c2f70
No dependencies set.
The note is not visible to the blocked user.
编号:D-03 严重级:medium 工作线:存储、配置、命令行与部署(internal/store、internal/config、cmd/nixmsg 命令、deploy) 来源:审查 P-14
依赖:C-01 (#32)、C-02 (#33)(推送改为先收集结果再发布、推送并发有上限) 被依赖:无
结论与统一方案
采用审查 P-14 的方案:
OpenReader设SetMaxIdleConns(16)、SetConnMaxIdleTime(5*time.Minute)、SetMaxOpenConns(64);读连接的 DSN 加_pragma=query_only(1)防止误写。前提是不存在"持有查询结果时又发第二个读查询"或"持有查询结果时做可能长时间阻塞的调用"。
message.pushReceipts目前边遍历查询结果边PublishDown,会长期占住读连接,需要先由 C-02 改成"先收集、再发布";C-01 的推送并发上限也要小于读池上限。改动文件
internal/store/db.go。与其他问题的交互 / 冲突说明
依赖 C-01、C-02,在它们之后合入。
验收与测试
db.Read.Stats().OpenConnections不超过上限。问题明细(各区审查原文,证据含文件与行号)
[P-14] 读连接池没有上限、只保留 2 个空闲连接:群发或批量唤醒时出现 SQLite 连接风暴
OpenReader没设连接池参数,默认不限打开数、只保留 2 个空闲连接。WakePush每个端起一个 goroutine。1000 人群发时,上千个 PushPending 同时读库,会打开上千个 SQLite 连接(每个 3 个文件句柄加页缓存,打开时还要执行 5 条 pragma),用完只留 2 个,下一波又重新打开。store/db.go:95-109;message/push.go:549-560。SetMaxIdleConns(16)、SetConnMaxIdleTime(5*time.Minute),SetMaxOpenConns设一个宽裕的上限(例如 64);读连接的 DSN 可以加_pragma=query_only(1)防止误写。internal/store/db.gomessage.pushReceipts就是边遍历查询结果边PublishDown,可能被 P-7 的慢客户端卡住,长期占着读连接。需要先请 M 线改成"先收集、再发布";P-7 的推送并发上限也要小于读池上限。db.Read.Stats().OpenConnections不超过上限。复审基线:main
4059a15(2026-09-30)。编号说明、各工作线的合并顺序、共享文件归属见总览 #7。D-03 已由 C-03 覆盖,本 issue 不另开补丁。 (#29)
feat/fix-message-c01-c03提交a4e51ec5cd中OpenReader:SetMaxOpenConns(64)、SetMaxIdleConns(16)、SetConnMaxIdleTime(5m),读 DSN_pragma=query_only(1)。测试
internal/store/db_pool_test.goTestReaderPoolCapAndQueryOnly:并发 200 读、OpenConnections<=64、读连接执行写语句报错。前提:C-01 每握手连接一个 push worker(不再每个
WakePush起 goroutine);C-02 回执先收集再发布。读池上限 64 可挡住群发连接风暴。未合入 main。已合入 origin/main
0c9b459。落地提交6a65ab8fix: 按完成时刻分批清理并限制读连接池 (#29)。store 侧见57c2f70。