From aba8346bd6c533ffb144258118e1100ff31e2cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 6 Feb 2026 22:28:30 +0800 Subject: [PATCH] Fix DNS cache lock goroutine leak The cache deduplication in Client.Exchange uses a channel-based lock per DNS question. Waiting goroutines blocked on <-cond without context awareness, causing them to accumulate indefinitely when the owning goroutine's transport call stalls. Add select on ctx.Done() so waiters respect context cancellation and timeouts. --- dns/client.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/dns/client.go b/dns/client.go index 939ca48c..2982d11c 100644 --- a/dns/client.go +++ b/dns/client.go @@ -144,7 +144,11 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m if c.cache != nil { cond, loaded := c.cacheLock.LoadOrStore(question, make(chan struct{})) if loaded { - <-cond + select { + case <-cond: + case <-ctx.Done(): + return nil, ctx.Err() + } } else { defer func() { c.cacheLock.Delete(question) @@ -154,7 +158,11 @@ func (c *Client) Exchange(ctx context.Context, transport adapter.DNSTransport, m } else if c.transportCache != nil { cond, loaded := c.transportCacheLock.LoadOrStore(question, make(chan struct{})) if loaded { - <-cond + select { + case <-cond: + case <-ctx.Done(): + return nil, ctx.Err() + } } else { defer func() { c.transportCacheLock.Delete(question)