Files
logan 2e97c04f84
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s
fix(db): 修复 NextID 与写锁重入死锁
- NextID 改用独立 seqMu,不再依赖数据写锁,杜绝 Lock 内调用 NextID 的死锁
- CaptureAppVolumeForHour 先取 ID 再 Lock
- 新增写锁看门狗:长时间占用时转储 goroutine 栈
- 新增 TestNextIDWhileWriteLocked 回归测试
2026-10-31 02:20:34 +08:00

36 lines
933 B
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package repository
import (
"testing"
"time"
)
// TestNextIDWhileWriteLocked 回归测试:调用方持有写锁时 NextID 不能死锁。
//
// 历史问题:NextID 内部用 d.mu 加锁,而 CaptureAppVolumeForHour 先 db.Lock()
// 再 db.NextID(),Go 的 sync.RWMutex 不可重入,导致该 goroutine 永久持有写锁,
// 所有读库接口(登录、列表)全部挂起,而 /health 仍然正常。
func TestNextIDWhileWriteLocked(t *testing.T) {
db := &JsonDB{sequences: map[string]uint{}}
db.Lock()
done := make(chan uint, 1)
go func() { done <- db.NextID("test") }()
select {
case id := <-done:
db.Unlock()
if id != 1 {
t.Fatalf("first id = %d, want 1", id)
}
case <-time.After(2 * time.Second):
db.Unlock()
t.Fatal("NextID deadlocked while write lock is held")
}
// 解锁后继续分配应递增
if id := db.NextID("test"); id != 2 {
t.Fatalf("second id = %d, want 2", id)
}
}