From fe366b2cf31b42e6736925f61b187cd0c38b1d2e Mon Sep 17 00:00:00 2001 From: Matt Schultz Date: Tue, 16 Mar 2021 18:07:24 -0500 Subject: [PATCH] Prevent panics caused by attempting to close an already closed pgxpool.Pool. --- pgxpool/pool.go | 10 ++++++++-- pgxpool/pool_test.go | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pgxpool/pool.go b/pgxpool/pool.go index 09752aaa..650c5970 100644 --- a/pgxpool/pool.go +++ b/pgxpool/pool.go @@ -326,8 +326,14 @@ func ParseConfig(connString string) (*Config, error) { // Close closes all connections in the pool and rejects future Acquire calls. Blocks until all connections are returned // to pool and closed. func (p *Pool) Close() { - close(p.closeChan) - p.p.Close() + // Check to see if the closeChan is closed before attempting to close it again, which can result in a panic. + select { + case <-p.closeChan: + // NOOP because the channel is already closed. + default: + close(p.closeChan) + p.p.Close() + } } func (p *Pool) backgroundHealthCheck() { diff --git a/pgxpool/pool_test.go b/pgxpool/pool_test.go index 965f342f..f6621df6 100644 --- a/pgxpool/pool_test.go +++ b/pgxpool/pool_test.go @@ -789,3 +789,14 @@ func TestTxBeginFuncNestedTransactionRollback(t *testing.T) { require.NoError(t, err) require.EqualValues(t, 2, n) } + +func TestIdempotentPoolClose(t *testing.T) { + pool, err := pgxpool.Connect(context.Background(), os.Getenv("PGX_TEST_DATABASE")) + require.NoError(t, err) + + // Close the open pool. + require.NotPanics(t, func() { pool.Close() }) + + // Close the already closed pool. + require.NotPanics(t, func() { pool.Close() }) +}