Skip to content

Commit 20578f5

Browse files
committed
feat: check if conn is expired before acquire
1 parent 5e5c1a2 commit 20578f5

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

pgxpool/pool.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,11 @@ func (p *Pool) Acquire(ctx context.Context) (c *Conn, err error) {
636636
}
637637
}
638638

639+
if isExpired := p.isExpired(res); isExpired {
640+
res.Destroy()
641+
continue
642+
}
643+
639644
if p.prepareConn != nil {
640645
ok, err := p.prepareConn(ctx, cr.conn)
641646
if !ok {

pgxpool/pool_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,48 @@ func TestPoolSendBatchBatchCloseTwice(t *testing.T) {
12821282
}
12831283
}
12841284

1285+
func TestPoolAcquireDestroysExpiredIdleConn(t *testing.T) {
1286+
t.Parallel()
1287+
1288+
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
1289+
defer cancel()
1290+
1291+
config, err := pgxpool.ParseConfig(os.Getenv("PGX_TEST_DATABASE"))
1292+
require.NoError(t, err)
1293+
1294+
config.MaxConnLifetime = 250 * time.Millisecond
1295+
config.HealthCheckPeriod = 10 * time.Second
1296+
1297+
pool, err := pgxpool.NewWithConfig(ctx, config)
1298+
require.NoError(t, err)
1299+
defer pool.Close()
1300+
1301+
// Acquire and release before expiry so the connection goes idle while still valid.
1302+
c, err := pool.Acquire(ctx)
1303+
require.NoError(t, err)
1304+
c.Release()
1305+
waitForReleaseToComplete()
1306+
1307+
require.EqualValues(t, 1, pool.Stat().TotalConns())
1308+
require.EqualValues(t, 0, pool.Stat().MaxLifetimeDestroyCount())
1309+
1310+
// Wait for the idle connection to expire.
1311+
time.Sleep(config.MaxConnLifetime + 100*time.Millisecond)
1312+
1313+
// Acquire should pick up the expired idle conn, the new isExpired check in Acquire
1314+
// destroys it, and a fresh connection is created.
1315+
c, err = pool.Acquire(ctx)
1316+
require.NoError(t, err)
1317+
c.Release()
1318+
1319+
// Give destroy time to settle.
1320+
time.Sleep(500 * time.Millisecond)
1321+
1322+
stats := pool.Stat()
1323+
require.EqualValues(t, 1, stats.MaxLifetimeDestroyCount())
1324+
require.EqualValues(t, 1, stats.TotalConns())
1325+
}
1326+
12851327
func TestPoolAcquirePingTimeout(t *testing.T) {
12861328
t.Parallel()
12871329

0 commit comments

Comments
 (0)