-
Notifications
You must be signed in to change notification settings - Fork 837
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Is it possible to disable the Ping that occurs when acquiring a connection in pgxpool? #1738
Comments
At the moment there is no way to configure or disable this. I'm not opposed to changing this, but if something is to be done it should be more flexible than a simple switch. Probably a user supplied function that returns true or false to determine if the connection should be considered fresh or needs to ping. |
Sure, is it something you see living on the |
Yes. |
Hi Jack, Was taking a look this morning at the code and had a question. What would you find useful to provide to the user to make the decision on whether or not they should do this liveness check? I'm not aware of everything that exists for use in the package, but right now it's using the // On the Config
CheckLiveness func(*puddle.Resource[*ConnResource]) bool
// Default func to use in the ParseConfig
func checkLiveness(res *puddle.Resource[*ConnResource]) bool {
return res.IdleDuration() > time.Second
}
// And the snippet in Acquire
cr := res.Value()
if p.checkLiveness(res) {
err := cr.conn.Ping(ctx)
if err != nil {
res.Destroy()
continue
}
} This would involve making Or do you want to pass something else to their user provided function? |
Hmm... Good question. I'm not super eager to make Maybe something like: type ShouldPingParams struct {
Conn *pgx.Conn
IdleDuration time.Duration
}
func ShouldPing(ctx context.Context, params ShouldPingParams) bool {
return params.IdleDuration > time.Second
} Using a struct allows us to add new variables in the future if we forgot something. The context is valuable to smuggle in any values from the outside as well as cancellation if for some reason the check is doing something that could block. |
Hi Jack, Sorry for the delay. Any issue with allocations of |
Since |
Ah ha, for some reason I was thinking because the struct had a pointer perhaps it would cause an issue, if that's not the case though then great. |
This is also an issue for The stdlib code unconditionally calls See related #272 Brought up in Vonng/pg_exporter#56 |
@db-instacart hey 👋 any plans on implementing this? Due to the current limitations, we're forced to use both v4 (PgBouncer) and v5 (Postgres) packages. I'd like to help, but I'm not sure I know enough about the project to do it well. |
Why not an interface? Something like: // On the Config
HealthCheck HealthChecker
// Default func to use in the ParseConfig
type HealthChecker interface {
ShouldCheckHealth(context.Context) bool
CheckHealth(context.Context, *pgx.Conn) error
}
type DefaultHealthChecker struct {
IdleDuration time.Duration
}
func (hc DefaultHealthChecker) ShouldCheckHealth(context.Context) bool {
return hc.IdleDuration > time.Second
}
// This so that users may iplement some custom way to check for the conection health
// Like how pg bouncer allows for sending a `do-nothing query` like `select 1`
func (hc DefaultHealthChecker) CheckHealth(ctx context.Context, con *pgx.Conn) error {
return con.Ping(ctx)
}
// And the snippet in Acquire
if ShouldCheckHealth(ctx) {
err := CheckHealth(ctx, cr.conn)
if err != nil {
res.Destroy()
continue
}
} Sorry if I'm missing something, just throwing a quick idea based on previous comments and a quick skim of the code |
@DEliasVCruz I'm not opposed to adding configuration to control how health is checked. But I think that should be a separate interface from deciding if health should be checked. It's quite possible someone would want to customize only one or the other and they shouldn't need to implement both. |
@jackc Understandable, then how about making it more granular? Asumming that there could be users who just want, the health check behaviour to be disable all together, having them implement a function whose only execution will be How about then having separate config options: // On the Config
type Config struct {
...
EnableHealthCheck bool // Defaults to true
HelthCheckConditionFunction func(ctx context.Context, map[string]any) bool
HelthCheckConditionParams map[string]any
HealthCheckQuery func(ctx context.Context, con *pgx.Conn) error
}
// Default function for Health Check Condition
func HelthCheckConditionFunction(ctx context.Context, params map[string]any) bool {
idleDuration, ok := params["idleDuration"].(time.Duration)
if !ok {
// I'm not sure what should be the expected behaviour in this case
return false
}
return idleDuration > time.Second
}
// Default function for Health Check Query
func HealthCheckQuery(ctx context.Context, con *pgx.Conn) error {
return con.Ping(ctx)
}
// And the snippet in Acquire
HelthCheckConditionParams["idleDuration"] = res.IdleDuration()
if EnableHealthCheck && HelthCheckConditionFunction(ctx, HelthCheckConditionParams) {
err := HealthCheckQuery(ctx, cr.conn)
if err != nil {
res.Destroy()
continue
}
} This way users who just want health check disabled can pass Using your idea of a struct for |
With
The point of |
pgx/pgxpool/pool.go
Lines 510 to 516 in b301530
I see it was added for:
Our use case is using pgx in read only proxies, so if this check is purely for
INSERT/UPDATE/DELETE
then it seems like we are doing extra pings that aren't needed.Possibly more noticeable for us as we have many pools configured, so likely connections can go idle for > 1 second.
Perhaps some config driven way to disable it?
The text was updated successfully, but these errors were encountered: