Files
3x-ui/internal/web/service/client_locks_test.go
T
MHSanaei ade3a8f870 fix(client): stop holding the inbound-lock registry mutex while waiting on one inbound
lockInbound acquired the global registry mutex and then blocked on the
per-inbound mutex without releasing the registry first. A slow client
operation holding one inbound's mutex (for example a bulk delete pushing to
an unreachable node) made the next waiter park on that inbound while still
holding the registry mutex, which in turn blocked lockInbound for every
other inbound — freezing client mutations panel-wide. Release the registry
mutex before taking the per-inbound lock.
2026-07-14 23:50:34 +02:00

30 lines
720 B
Go

package service
import (
"testing"
"time"
)
// lockInbound must not hold the global registry mutex while it waits on a busy
// inbound's own mutex, otherwise one slow client operation on a single inbound
// freezes client mutations on every other inbound panel-wide.
func TestLockInboundReleasesRegistryMutexWhileWaiting(t *testing.T) {
const id = 990006
held := lockInbound(id)
parked := make(chan struct{})
go func() {
close(parked)
lockInbound(id).Unlock()
}()
<-parked
time.Sleep(50 * time.Millisecond)
if !inboundMutationLocksMu.TryLock() {
held.Unlock()
t.Fatal("registry mutex is held while a lockInbound caller waits on a busy inbound")
}
inboundMutationLocksMu.Unlock()
held.Unlock()
}