[R3-03][medium] 写队列满时关闭会与入队互相卡住 #67

Closed
opened 2026-09-30 17:18:25 +08:00 by nixevol · 2 comments
Owner

现象

基线 origin/main 0c9b459。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、Drain
  • cmd/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。

## 现象 基线 `origin/main` `0c9b459`。`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`、`Drain` - `cmd/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`。
Author
Owner

???: eat/fix-r3-67-queue @ eb4cb7c655e5bb6796c2514aaa4a714d0b4c3b3e

??

  • enqueue ? sendMu.RLock ?? select ??? q.ch / closing / ctx.Done(),?????????
  • Close ????? close(closing) ???????,??????? close(q.ch),???????? goroutine ???

??

  • go test ./internal/store/ -count=1 -run "Queue|WriteQueue" ??(???? + ????? Close / ?? Drain)

?? main?

???: eat/fix-r3-67-queue @ `eb4cb7c655e5bb6796c2514aaa4a714d0b4c3b3e` **??** - enqueue ? sendMu.RLock ?? select ??? q.ch / closing / ctx.Done(),????????? - Close ????? close(closing) ???????,??????? close(q.ch),???????? goroutine ??? **??** - go test ./internal/store/ -count=1 -run "Queue|WriteQueue" ??(???? + ????? Close / ?? Drain) ?? main?
Author
Owner

已合入 main:aa38cfc (#67);当前 origin/main HEAD 2d1dfd7。

已合入 main:`aa38cfc` (#67);当前 origin/main HEAD `2d1dfd7`。
Sign in to join this conversation.