pgx icon indicating copy to clipboard operation
pgx copied to clipboard

pgxpool: acquire wait time stats

Open redbaron opened this issue 2 years ago • 4 comments

Is your feature request related to a problem? Please describe. I'd like to better understand the impact of a fully utilized connection pool. That is the case when there is no idle connections and app tries to acquire one.

There is Stat.EmptyAcquireCount, which is a good start, but it doesn't give full picture. I'd like to be able to get a histogram of times app waited for connection

Describe the solution you'd like Histogram could be taken if there were OnAcquireStart and OnAcquireComplete, which are called as the very first and very last operation in Pool.Acquire. Alternatively pgxpool could expose histogram in the Stat.

Describe alternatives you've considered Creting own wrapper around Pool.Acquire func, but this requires changing all call-sites in the app.

Additional context Add any other context or screenshots about the feature request here.

redbaron avatar Jul 02 '23 15:07 redbaron

Histogram could be taken if there were OnAcquireStart and OnAcquireComplete, which are called as the very first and very last operation in Pool.Acquire. Alternatively pgxpool could expose histogram in the Stat.

If this is to be done, at least some of the change should be done in the puddle library. Getting the time is cheap, but not free, and it is already done internally in the puddle acquire logic. It might make sense to add a field to puddle.Resource for acquire duration (maybe other fields to like whether a new resource was created, whether it blocked, etc.).

Then the changes in pgxpool would be smaller as well.

jackc avatar Jul 07 '23 00:07 jackc

What we do is a bit hacky but essentially:

cfg.BeforeAcquire = func(ctx context.Context, c *pgx.Conn) bool {
  t, ok := ctx.Value(contextKeyAcquired).(*time.Time)
  if ok {
    *t = time.Now()
  }
  return true
}
...
var acquired time.Time
ctx = context.WithValue(ctx, contextKeyAcquired, &acquired)
now := time.Now()
pool.Exec(ctx, ...)
waiting := acquired.Sub(now)

jameshartig avatar Jul 20 '23 03:07 jameshartig

So even with both the above PRs, we would still not be able to get a histogram of how much time it took to acquire the connection, right?

I am not very well versed with pgx code base, but can we leverage acquire tracer to do this?

	if p.acquireTracer != nil {
		ctx = p.acquireTracer.TraceAcquireStart(ctx, p, TraceAcquireStartData{})
		defer func() {
			var conn *pgx.Conn
			if c != nil {
				conn = c.Conn()
			}
			p.acquireTracer.TraceAcquireEnd(ctx, p, TraceAcquireEndData{Conn: conn, Err: err})
		}()
	}

It seems like passing the start time in context in TraceAcquireStart and reading in TraceAcquireEnd and registering in a histogram would work?

vamshiaruru avatar Dec 27 '24 09:12 vamshiaruru

+1 I need this feature

Shion1305 avatar May 15 '25 01:05 Shion1305