package services import ( "testing" "time" "lokistack/repository" ) // 回归:持写锁时裁剪逻辑绝不能再去拿读锁。 // // 线上事故:一个 day-retention 配置读取被写成在 db.Lock() 内部调用 // GetRetentionSettings()(内部 db.RLock())。Go 的 sync.RWMutex 不可重入, // 于是**第一次写投递历史/审计日志就永久死锁** —— 平台表现是"登录 28 秒返回空", // 因为登录也要写审计。go build / go vet / 单测(不触发写路径)全都查不出来。 func TestPruneWhileLockedDoesNotDeadlock(t *testing.T) { db := &repository.JsonDB{} db.Lock() defer db.Unlock() done := make(chan struct{}) go func() { defer close(done) pruneDeliveriesLocked(db) }() select { case <-done: case <-time.After(2 * time.Second): t.Fatal("pruneDeliveriesLocked 在持有写锁时死锁(内部又去拿了读锁)") } } // 同理:审计日志裁剪。 func TestPruneAuditWhileLockedDoesNotDeadlock(t *testing.T) { db := &repository.JsonDB{} db.Lock() defer db.Unlock() done := make(chan struct{}) go func() { defer close(done) pruneAuditLocked(db) }() select { case <-done: case <-time.After(2 * time.Second): t.Fatal("pruneAuditLocked 在持有写锁时死锁(内部又去拿了读锁)") } }