From 6a48d3fec17274e59a9f5d401558693c1f6c5fb9 Mon Sep 17 00:00:00 2001 From: Monkey Date: Tue, 5 Aug 2025 20:31:58 +0800 Subject: [PATCH] feat: recover addIdleConn may occur panic (#2445) * feat: recover addIdleConn may occur panic Signed-off-by: monkey92t * fix test race Signed-off-by: monkey92t --------- Signed-off-by: monkey92t Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com> --- internal/pool/export_test.go | 10 ++++++++++ internal/pool/pool.go | 12 ++++++++++++ internal/pool/pool_test.go | 18 ++++++++++++++++++ 3 files changed, 40 insertions(+) diff --git a/internal/pool/export_test.go b/internal/pool/export_test.go index f3a65f86..40e387c9 100644 --- a/internal/pool/export_test.go +++ b/internal/pool/export_test.go @@ -12,3 +12,13 @@ func (cn *Conn) SetCreatedAt(tm time.Time) { func (cn *Conn) NetConn() net.Conn { return cn.netConn } + +func (p *ConnPool) CheckMinIdleConns() { + p.connsMu.Lock() + p.checkMinIdleConns() + p.connsMu.Unlock() +} + +func (p *ConnPool) QueueLen() int { + return len(p.queue) +} diff --git a/internal/pool/pool.go b/internal/pool/pool.go index 6d3381c9..9644cb85 100644 --- a/internal/pool/pool.go +++ b/internal/pool/pool.go @@ -130,6 +130,18 @@ func (p *ConnPool) checkMinIdleConns() { p.idleConnsLen++ go func() { + defer func() { + if err := recover(); err != nil { + p.connsMu.Lock() + p.poolSize-- + p.idleConnsLen-- + p.connsMu.Unlock() + + p.freeTurn() + internal.Logger.Printf(context.Background(), "addIdleConn panic: %+v", err) + } + }() + err := p.addIdleConn() if err != nil && err != ErrClosed { p.connsMu.Lock() diff --git a/internal/pool/pool_test.go b/internal/pool/pool_test.go index 05949e42..736323d9 100644 --- a/internal/pool/pool_test.go +++ b/internal/pool/pool_test.go @@ -361,6 +361,24 @@ var _ = Describe("race", func() { Expect(stats.TotalConns).To(Equal(uint32(opt.PoolSize))) }) + It("recover addIdleConn panic", func() { + opt := &pool.Options{ + Dialer: func(ctx context.Context) (net.Conn, error) { + panic("test panic") + }, + PoolSize: 100, + MinIdleConns: 30, + } + p := pool.NewConnPool(opt) + + p.CheckMinIdleConns() + + Eventually(func() bool { + state := p.Stats() + return state.TotalConns == 0 && state.IdleConns == 0 && p.QueueLen() == 0 + }, "3s", "50ms").Should(BeTrue()) + }) + It("wait", func() { opt := &pool.Options{ Dialer: func(ctx context.Context) (net.Conn, error) {