2
0

Check conn liveness before using when idle for more than 1 second

Implemented in pgxpool.Pool and database/sql.

https://github.com/jackc/pgx/issues/672
This commit is contained in:
Jack Christensen
2022-06-25 17:58:53 -05:00
parent 26eda0f86d
commit 03da9fcec6
4 changed files with 139 additions and 5 deletions
+9
View File
@@ -417,6 +417,15 @@ func (p *Pool) Acquire(ctx context.Context) (*Conn, error) {
}
cr := res.Value()
if res.IdleDuration() > time.Second {
err := cr.conn.PgConn().CheckConn()
if err != nil {
res.Destroy()
continue
}
}
if p.beforeAcquire == nil || p.beforeAcquire(ctx, cr.conn) {
return cr.getConn(p, res), nil
}
+52
View File
@@ -11,6 +11,7 @@ import (
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/jackc/pgx/v5/pgxtest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -141,6 +142,57 @@ func TestPoolAcquireAndConnHijack(t *testing.T) {
require.Equal(t, int32(1), n)
}
func TestPoolAcquireChecksIdleConns(t *testing.T) {
t.Parallel()
controllerConn, err := pgx.Connect(context.Background(), os.Getenv("PGX_TEST_DATABASE"))
require.NoError(t, err)
defer controllerConn.Close(context.Background())
pgxtest.SkipCockroachDB(t, controllerConn, "Server does not support pg_terminate_backend() (https://github.com/cockroachdb/cockroach/issues/35897)")
pool, err := pgxpool.Connect(context.Background(), os.Getenv("PGX_TEST_DATABASE"))
require.NoError(t, err)
defer pool.Close()
var conns []*pgxpool.Conn
for i := 0; i < 3; i++ {
c, err := pool.Acquire(context.Background())
require.NoError(t, err)
conns = append(conns, c)
}
require.EqualValues(t, 3, pool.Stat().TotalConns())
var pids []uint32
for _, c := range conns {
pids = append(pids, c.Conn().PgConn().PID())
c.Release()
}
_, err = controllerConn.Exec(context.Background(), `select pg_terminate_backend(n) from unnest($1::int[]) n`, pids)
require.NoError(t, err)
// All conns are dead they don't know it and neither does the pool.
require.EqualValues(t, 3, pool.Stat().TotalConns())
// Wait long enough so the pool will realize it needs to check the connections.
time.Sleep(time.Second)
// Pool should try all existing connections and find them dead, then create a new connection which should successfully ping.
err = pool.Ping(context.Background())
require.NoError(t, err)
// The original 3 conns should have been terminated and the a new conn established for the ping.
require.EqualValues(t, 1, pool.Stat().TotalConns())
c, err := pool.Acquire(context.Background())
require.NoError(t, err)
cPID := c.Conn().PgConn().PID()
c.Release()
require.NotContains(t, pids, cPID)
}
func TestPoolAcquireFunc(t *testing.T) {
t.Parallel()