-
Notifications
You must be signed in to change notification settings - Fork 146
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
Automatically drop all connections after fork #166
Conversation
Here's what keeping track of instances in a WeakMap would involve: casperisfine@3ff19dd. |
lib/connection_pool.rb
Outdated
# We're on after fork, so we know all other threads are dead. | ||
# All we need to do is to ensure the main thread doesn't have a | ||
# checked out connection | ||
pool.checkin(force: true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this code running in the child main thread? Any main thread connection would have been checked out by the parent process's main thread. Will that use the same thread locals?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will that use the same thread locals?
yes, the main thread state is kept.
So this codepath is to handle code such as:
pool.checkout
fork
or
pool.with do
fork
end
Fix: mperham#165 Using connections inherited from a parent process can have very nasty consequences and it's pretty much never desired. This patch use the `Process._fork` API added in Ruby 3.1 to automatically detect when a fork is happening, and when it does, drop all existing connections.
64c09b7
to
e197083
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me.
This is much faster than relying on `ObjectSpace.each_object`
e197083
to
eca04dc
Compare
Thanks! ❤️ |
A new release is planned to integrate this PR? |
Eventually. Do you need it soon for some reason? |
Periodically, nearly restart or scaling event, we have more connections open than the theoretical count. We don't investigate a lot because we have needed to upscale Redis plan for other reasons and pics it's never more than 2x higher than the theoretical count. But we would appreciate updating our gem with this feature only to see if it resolves our problem. |
You could run main, right? |
We could. It's not very clean, but we could. |
I could use the feedback, let me know if it helps. Not sure what you mean by clean, it’s one line in your Gemfile. |
We've been running 428c06f for a couple months now without any issues on a system that's probably processed 40 million jobs over the time. |
2.4.0 is out with this new feature. |
Fix: mperham/connection_pool#172 Ref: mperham/connection_pool#166 ConnectionPool descendants must accept `checking(force: true)`. When it's called, all the cached connection should be checked back in, and the `Thread.current` state reset. Additionally, making `Connection` respond to `close` allow them to be automatically closed on fork.
Fix: #165
Using connections inherited from a parent process can have very nasty consequences and it's pretty much never desired.
This patch use the
Process._fork
API added in Ruby 3.1 to automatically detect when a fork is happening, and when it does, drop all existing connections.Notes
Performance
ObjectSpace.each_object
is very slow for large applications:So I'd really recommend to keep track of instance with
ObjectSpace::WeakMap
. I'll push a commit in another branch and let you decide.Connection closing
Since
ConnectionPool
doesn't know how to close a connection, this feature simply drop the references, and assume the Ruby GC will do the right thing.