`BeforeConnect` receives `context.Background()` (instead of the pool context) from the healthcheck path
- Dominant language
- Go
- Stars
- 14.3k
- Forks
- 1.1k
- Avg merge
- 6d 9h
- Merged PRs (30d)
- 11
Description
**Describe the bug**
Long story short, we use `BeforeConnect` to implement IAM Authentication with AWS / Aurora, and I traced back some panics to a missing logger in the context passed to BeforeConnect. I would expect the hook to receive a useful context (for logging, tracing, fetching credentials, ...), but while that happens for `Pool.Acquire`, the background goroutine refilling the pool to satisfy the minimum size calls it with a bare `context.Background()`.
**To Reproduce**
Steps to reproduce the behavior:
```go
package main
import (
"context"
"fmt"
"time"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool"
)
type key int
const myKey key = 0
func main() {
ctx := context.WithValue(context.Background(), myKey, "value")
poolConfig, _ := pgxpool.ParseConfig("postgres://user:password@127.0.0.1:1/mydb")
// Fail fast
poolConfig.ConnConfig.ConnectTimeout = 200 * time.Millisecond
// Prepare connections in the background
poolConfig.MinConns = 1
poolConfig.HealthCheckPeriod = 300 * time.Millisecond
var calls int
poolConfig.BeforeConnect = func(bcCtx context.Context, cc *pgx.ConnConfig) error {
calls++
if v := bcCtx.Value(myKey); v == nil {
fmt.Printf("call %d: BeforeConnect ctx MISSING value\n", calls)
} else {
fmt.Printf("call %d: BeforeConnect ctx has value=%q\n", calls, v)
}
return nil
}
pool, err := pgxpool.NewWithConfig(ctx, poolConfig)
if err != nil {
panic(err)
}
defer pool.Close()
// Let the background healthcheck fire a few times.
time.Sleep(2 * time.Second)
}
```
**Expected behavior**
```
call 1: ctx has value="value"
call 2: ctx has value="value"
call 3: ctx has value="value"
```
**Actual behavior**
```
call 1: ctx has value="value"
call 2: ctx MISSING value
call 3: ctx MISSING value
```
Call 1 comes from the initial idle creation goroutine in `NewWithConfig`. The subsequent ones come from `backgroundHealthCheck` + `checkMinConns`.
**Impact**
Anyone relying on `context.Value` propagation in `BeforeConnect` (e.g. injecting a request-scoped logger or AWS credential cache) sees inconsistent errors: the hook works on `Acquire`, it works on initial pool warm-up, but it randomly breaks on background refills. In our case it caused a nil-pointer panic while trying to log a message about the authentication.
Either re-use the context passed to `NewWithConfig`, expose a new `Config.HealthCheckContext`, or at the very least document the behavior to avoid unpleasant surprises. I can have a go at the first option if there's agreement.
**Version**
- Go: go1.26.2 darwin/arm64
- pgx: v5.9.1
- puddle: v2.2.2
Contributor guide
Research direction
Start at pgxpool.NewWithConfig and trace the initial idle creation path alongside backgroundHealthCheck and checkMinConns. Compare the contexts reaching BeforeConnect from initial creation, Acquire, and healthcheck refills. Done means the intended context behavior is defined and the reproduction is covered by tests for repeated healthcheck-driven connections.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, go, postgresql
- Domain
- database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100