-
Notifications
You must be signed in to change notification settings - Fork 853
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
Pool triggerHealthCheck leaves stranded goroutines for 500ms #1641
Comments
But the goroutine terminates after that 500ms, right? Does this behavior cause a problem? |
@jackc I think the primary issues are:
From a brief look at the code in t := time.NewTimer(500*time.Millisecond)
select {
case <-p.closeChan:
if !t.Stop() {
<-t.C
}
return
case <-t.C:
select {
case p.healthCheckChan <- struct{}{}:
default:
}
} This of course doesn't 100% solve the fact that the goroutine could still be running for a brief moment after the return of I also see that elsewhere in the code you're doing something similar to the above pattern, except using a |
🤷♂️
The docs say all connections are closed, and they are. The fact that health checks are implemented via a background goroutine is an implementation detail that isn't exposed through the public interface.
That is unfortunate, but I view it as akin to checking memory usage as soon as a value has gone out of scope. The GC may not have run yet. Once a variable is out of scope or a Pool is closed it's not visible to the user application unless runtime introspection is used. I don't mind if someone wants to refactor / improve this, but it's not something I personally plan on working on. |
@jackc I opened #1642 to at least try to improve these situations, although it doesn't fully resolve the potential goleak issue. At least the workaround is documented here in case anybody goes looking for it. If in spite of the PR you don't feel this is worth fixing, no worries, feel free to close this and the PR. Thanks for your great work on pgx regardless ✌️ |
When a pool is closed, some background goroutines may be left open, particularly for health checks as detailed in jackc#1641. Two specific examples have been refactored here to avoid a blocking sleep and instead also select on the pool being closed to potentially return/continue sooner.
Describe the bug
After releasing all conns back to a
pgxpool.Pool
and closing the pool, there can still be goroutines left running. That's becausetriggerHealthCheck
gets called uponRelease()
, and it spawns a goroutine which begins by sleeping 500ms no matter what.This means there is no way to guarantee that a pgxpool is fully shut down with no remaining remnants, at least not without sleeping a non-trivial amount of time.
To Reproduce
I can try to put together a reproduction if it helps. I believe this is triggered by:
goleak
in your test programgoleak
sometimes detects open/leaked goroutines when the program exits.Expected behavior
Closing a
pgxpool.Pool
should leave behind no remnants and no open goroutines.Actual behavior
Because there is a hardcoded 500ms sleep that doesn't terminate when i.e. the pool closes sooner, goroutines are sometimes left running after the pool is closed.
Version
$ go version
->go version go1.20.4 darwin/amd64
$ psql --no-psqlrc --tuples-only -c 'select version()'
->PostgreSQL 14.8 (Homebrew) on x86_64-apple-darwin22.4.0, compiled by Apple clang version 14.0.3 (clang-1403.0.22.14.1), 64-bit
$ grep 'github.com/jackc/pgx/v[0-9]' go.mod
->github.com/jackc/pgx/v5 v5.3.1
Additional context
I did not see any past issues discussing this, so I wanted to at least confirm that it was an intentional design choice and not merely an oversight or bug.
The text was updated successfully, but these errors were encountered: