Skip to content

Commit cc7ddf3

Browse files
jackcclaude
andcommitted
Fix MaxLifetimeDestroyCount and ping order for acquire-time expiry check
The acquire-time expiry check destroyed expired connections without incrementing lifetimeDestroyCount, unlike the equivalent checks in Conn.Release and checkConnsHealth. This undercounted retired connections in pool stats and made TestPoolAcquireDestroysExpiredIdleConn fail. Also move the expiry check ahead of the ping so an expired connection is destroyed without first incurring a wasted ping round-trip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 20578f5 commit cc7ddf3

1 file changed

Lines changed: 9 additions & 5 deletions

File tree

pgxpool/pool.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -619,6 +619,15 @@ func (p *Pool) Acquire(ctx context.Context) (c *Conn, err error) {
619619

620620
cr := res.Value()
621621

622+
// Destroy expired connections before doing any further work (such as
623+
// pinging) on them. This enforces MaxConnLifetime at acquire time so that
624+
// a connection that expired while idle on a busy pool is not handed out.
625+
if p.isExpired(res) {
626+
atomic.AddInt64(&p.lifetimeDestroyCount, 1)
627+
res.Destroy()
628+
continue
629+
}
630+
622631
shouldPingParams := ShouldPingParams{Conn: cr.conn, IdleDuration: res.IdleDuration()}
623632
if p.shouldPing(ctx, shouldPingParams) {
624633
err := func() error {
@@ -636,11 +645,6 @@ func (p *Pool) Acquire(ctx context.Context) (c *Conn, err error) {
636645
}
637646
}
638647

639-
if isExpired := p.isExpired(res); isExpired {
640-
res.Destroy()
641-
continue
642-
}
643-
644648
if p.prepareConn != nil {
645649
ok, err := p.prepareConn(ctx, cr.conn)
646650
if !ok {

0 commit comments

Comments
 (0)