diff --git a/conn_pool.go b/conn_pool.go index 0e04268e..cd8b7f63 100644 --- a/conn_pool.go +++ b/conn_pool.go @@ -228,13 +228,19 @@ func (p *ConnPool) BeginIso(iso string) (*Tx, error) { } tx, err := c.BeginIso(iso) - if err == ErrDeadConn { - p.Release(c) - continue - } if err != nil { + alive := c.IsAlive() p.Release(c) - return nil, err + + // If connection is still alive then the error is not something trying + // again on a new connection would fix, so just return the error. But + // if the connection is dead try to acquire a new connection and try + // again. + if alive { + return nil, err + } else { + continue + } } tx.pool = p diff --git a/conn_pool_test.go b/conn_pool_test.go index 74c03a2b..73519855 100644 --- a/conn_pool_test.go +++ b/conn_pool_test.go @@ -363,41 +363,46 @@ func TestConnPoolTransactionIso(t *testing.T) { func TestConnPoolBeginRetry(t *testing.T) { t.Parallel() - pool := createConnPool(t, 2) - defer pool.Close() + // Run timing sensitive test many times + for i := 0; i < 50; i++ { + func() { + pool := createConnPool(t, 2) + defer pool.Close() - killerConn, err := pool.Acquire() - if err != nil { - t.Fatal(err) - } - defer pool.Release(killerConn) + killerConn, err := pool.Acquire() + if err != nil { + t.Fatal(err) + } + defer pool.Release(killerConn) - victimConn, err := pool.Acquire() - if err != nil { - t.Fatal(err) - } - pool.Release(victimConn) + victimConn, err := pool.Acquire() + if err != nil { + t.Fatal(err) + } + pool.Release(victimConn) - // Terminate connection that was released to pool - if _, err = killerConn.Exec("select pg_terminate_backend($1)", victimConn.Pid); err != nil { - t.Fatalf("Unable to kill backend PostgreSQL process: %v", err) - } + // Terminate connection that was released to pool + if _, err = killerConn.Exec("select pg_terminate_backend($1)", victimConn.Pid); err != nil { + t.Fatalf("Unable to kill backend PostgreSQL process: %v", err) + } - // Since victimConn is the only available connection in the pool, pool.Begin should - // try to use it, fail, and allocate another connection - tx, err := pool.Begin() - if err != nil { - t.Fatalf("pool.Begin failed: %v", err) - } - defer tx.Rollback() + // Since victimConn is the only available connection in the pool, pool.Begin should + // try to use it, fail, and allocate another connection + tx, err := pool.Begin() + if err != nil { + t.Fatalf("pool.Begin failed: %v", err) + } + defer tx.Rollback() - var txPid int32 - err = tx.QueryRow("select pg_backend_pid()").Scan(&txPid) - if err != nil { - t.Fatalf("tx.QueryRow Scan failed: %v", err) - } - if txPid == victimConn.Pid { - t.Error("Expected txPid to defer from killed conn pid, but it didn't") + var txPid int32 + err = tx.QueryRow("select pg_backend_pid()").Scan(&txPid) + if err != nil { + t.Fatalf("tx.QueryRow Scan failed: %v", err) + } + if txPid == victimConn.Pid { + t.Error("Expected txPid to defer from killed conn pid, but it didn't") + } + }() } }