基线 origin/main 0c9b459。enqueue 持有 sendMu.RLock 后阻塞在 q.ch <- job。通道缓冲 1024 被写满时,并发 Do 会一直占着读锁。Close 需要 sendMu.Lock 才能 close(q.ch),因此拿不到锁。Drain 又看到 pending>0 等不到 0。停机走 Drain 再 db.Close() 时进程退不出去,只能被强杀,已入队未提交的写会丢。
origin/main
0c9b459
enqueue
sendMu.RLock
q.ch <- job
Do
Close
sendMu.Lock
close(q.ch)
Drain
pending>0
db.Close()
这和已修的「向已关闭 channel 发送 panic」不是同一件事。
internal/store/queue.go
cmd/nixmsg/serve.go
db.Queue.Drain
defer db.Close()
入队不要在持有 sendMu 的情况下无限阻塞发送。关闭时要能打断堵在满通道上的发送者。
sendMu
可用的做法:用单独的 closing 信号。发送用 select 同时等待 q.ch 和 closing。Close 先置关闭标志并关闭 closing,等在途发送退出,再在没有发送者时关闭 q.ch。已经在通道里的任务仍由写 goroutine 处理完。Drain 的超时必须能返回,不能因为死锁永远等。
closing
select
q.ch
补测试:把通道填满并堵住写 goroutine,再调用 Close 或带超时的 Drain,应在短时间内返回,而不是死锁。
只改 internal/store/queue.go 与 internal/store/queue_test.go。不要改迁移编号。偏差节 ### 复审修复 R3-03。
internal/store/queue_test.go
### 复审修复 R3-03
???:eat/fix-r3-67-queue @ eb4cb7c655e5bb6796c2514aaa4a714d0b4c3b3e
eb4cb7c655e5bb6796c2514aaa4a714d0b4c3b3e
??
?? main?
已合入 main:aa38cfc (#67);当前 origin/main HEAD 2d1dfd7。
aa38cfc
2d1dfd7
No dependencies set.
The note is not visible to the blocked user.
现象
基线
origin/main0c9b459。enqueue持有sendMu.RLock后阻塞在q.ch <- job。通道缓冲 1024 被写满时,并发Do会一直占着读锁。Close需要sendMu.Lock才能close(q.ch),因此拿不到锁。Drain又看到pending>0等不到 0。停机走Drain再db.Close()时进程退不出去,只能被强杀,已入队未提交的写会丢。这和已修的「向已关闭 channel 发送 panic」不是同一件事。
位置
internal/store/queue.go:enqueue、Close、Draincmd/nixmsg/serve.go:停机时db.Queue.Drain与defer db.Close()方案
入队不要在持有
sendMu的情况下无限阻塞发送。关闭时要能打断堵在满通道上的发送者。可用的做法:用单独的
closing信号。发送用select同时等待q.ch和closing。Close先置关闭标志并关闭closing,等在途发送退出,再在没有发送者时关闭q.ch。已经在通道里的任务仍由写 goroutine 处理完。Drain的超时必须能返回,不能因为死锁永远等。补测试:把通道填满并堵住写 goroutine,再调用
Close或带超时的Drain,应在短时间内返回,而不是死锁。约束
只改
internal/store/queue.go与internal/store/queue_test.go。不要改迁移编号。偏差节### 复审修复 R3-03。???:eat/fix-r3-67-queue @
eb4cb7c655e5bb6796c2514aaa4a714d0b4c3b3e??
??
?? main?
已合入 main:
aa38cfc(#67);当前 origin/main HEAD2d1dfd7。