This project is archived and is in readonly mode.
Modifying with_connection method
Reported by ronin-37814 (at lighthouseapp) | January 13th, 2009 @ 10:36 PM | in 2.x
More useful version of with_connection. If you wrap all your code which makes AR queries with this method you don't have to worry about connection cleanup. It simply release the connection when the block is done. It also protects against releasing the connection inside of nested calls, it will only release when the topmost call completes (see test for example of this)
The following code will leave 1 connection checked out of the connection pool
Thread.new do
ActiveRecord::Base.connection_pool.with_connection do |this_conn_isnt_actually_used|
User.all
end
end.join
But with cleanup_connection the connection will be checked in after the block completes. The connection pool will be in its original state when this code finishes.
Thread.new do
ActiveRecord::Base.connection_pool.cleanup_connection do
User.all
end
end.join
Comments and changes to this ticket
-
Pratik January 13th, 2009 @ 11:03 PM
- Tag changed from patch to activerecord, connection, patch, pool
- Assigned user set to Pratik
- Title changed from added using_connection method; like with_connection but sets it as default connection while inside the block to Adding using_connection method
-
ronin-37814 (at lighthouseapp) January 14th, 2009 @ 06:29 AM
example of why nesting protection is very helpful
def x using_connection do User.all.each {|u| y(u) } end end def y(u) using_connection do u.something = rand u.save! end end def z y(@user) end
Basically it allows you to only wrap code which is immediately doing an AR update without having to worry about nesting issues.
-
ronin-37814 (at lighthouseapp) January 14th, 2009 @ 07:58 PM
- Title changed from Adding using_connection method to Adding cleanup_connection method
Realized all I really care about is cleaning up the connection at the end of the block, so here's a simpler version. It doesn't explicitly check out the connection. That will be done by AR on the first call to AR::B.connection.
Test for nesting safety added.
-
ronin-37814 (at lighthouseapp) January 14th, 2009 @ 10:03 PM
added more real-world test case for nesting safety
-
ronin-37814 (at lighthouseapp) January 14th, 2009 @ 10:05 PM
renamed thread local variable to cleanup_connection
-
Michael Lang February 4th, 2009 @ 05:35 AM
+1
This patch lets me use ActiveRecord in Ramaze. A most timely patch.
-
ronin-37814 (at lighthouseapp) February 17th, 2009 @ 09:31 PM
Moved cleanup_connection method to ConnectionHandler. Using clear_active_connections! instead of release_connection so we release connections from all connection pools in use by the current thread.
-
ronin-37814 (at lighthouseapp) February 17th, 2009 @ 10:25 PM
As requested by lifo
Real World Usecase:
You have 100 threads which stay alive and running throughout the entire life of your process. These threads are intermittently doing AR calls. Now assume you can't or don't want to increase your connection pool size to 100. Or assume instead of 100 its some unknown number of threads which might be higher than you can set your connection pool size to.
Without this patch each thread will hold onto a single connection even though it's not making use of it most of the time. With this patch you can wrap all your AR access in a cleanup_connection block and the thread will release the connection whenever its finished with it. This will allow you to get away with a small connection pool even with lots of threads using AR.
-
Nick Sieger February 17th, 2009 @ 10:48 PM
I can appreciate the desire for this patch, but what about just piggy-backing off the existing connection method instead? Consider this patch:
It's just a proof-of-concept, may need some cleaning up and adding tests/merging w/ coderrr's patch.
What do you think?
-
ronin-37814 (at lighthouseapp) February 17th, 2009 @ 11:01 PM
Hey nick
The only issue with that is that if you have multiple connections (in different AR models) you'd need to do a connection call for each of them. If you forgot to do that these connections would remain open in the thread.
User.connection { Project.connection { ... } }
Not that big deal. Other than that I don't really have any objection to piggybacking.
-
Nick Sieger February 18th, 2009 @ 01:48 AM
If you're satisfied with that pattern, we could push the logic up to the AR::Base class method to do the cleanup and it could do so with clear_active_connections! like you have in your patch.
Any other thoughts about the overloading of AR::Base.connection?
-
Nick Sieger February 18th, 2009 @ 08:28 PM
Here's a patch w/ coderrr's tests and my approach with passing the block down through AR::Base.connection.
-
Michael Koziarski February 18th, 2009 @ 08:52 PM
Don't we already have a with_connection method on the connection pool?
Perhaps we just make that available from AR::Base more simply?
-
ronin-37814 (at lighthouseapp) February 18th, 2009 @ 08:55 PM
with_connection isn't good enough. It only releases the connection which it checks out. And the connection it checks out will be different from AR::B#connection
-
Nick Sieger February 19th, 2009 @ 05:04 PM
Koz: with_connection doesn't associate the connection with the thread, so that regular code like Model.find would still pull another connection. That's yet another option to make with_connection stash the connection away in the thread if it isn't there.
-
Michael Koziarski February 19th, 2009 @ 07:01 PM
Just seems to me like unless there's a reason that with_connection shouldn't do that, then it'd be cleaner than messing with .connection
What's the behaviour of this new method if a connection is already checked out, does it check out another and replace all the thread locals?
-
ronin-37814 (at lighthouseapp) February 19th, 2009 @ 07:10 PM
Well there are two versions...
In the original version (cleanup_connection method), if a connection is already checked out it won't check out a new one. But will release it when the block completes.
In the latest version it wouldn't check out a new connection either but also wouldn't release the connection afterwards.
I don't have a problem with putting the functionality in with_connection. I agree changing connection method is a heavier change, even though without a block it would function as before. I really don't care where this functionality ends up, but at this point if I had to vote, it seems that modifying the connection method would be cleanest and point people in the right direction in terms of checkins/checkout.
-
Jacob Burkhart February 26th, 2009 @ 04:01 PM
I've noticed that ActiveRecord::Base.connection_pool.with_connection doesn't override the connection for all your models...
If you plan to
ActiveRecord::Base.connection_pool.with_connection do |conn|
u = User.new u.save!
end
then your user object is not saved with the connection you opened with_connection. Instead you have to do:
User.connection_pool.with_connection do |conn|
u = User.new u.save!
end
Is this by design? Why?
If we change is_connection to:
def with_connection conn = checkout old_conn = @reserved_connections[current_connection_id] @reserved_connections[current_connection_id] = conn yield conn ensure checkin conn @reserved_connections[current_connection_id] = old_conn end
Then it works as I had expected it should.
-
ronin-37814 (at lighthouseapp) February 26th, 2009 @ 04:08 PM
Yes, the issue you pointed out is exactly why I created this ticket.
We need more than what your implementation of with_connection provides. If you have nested calls to with_connection you'll check out a new connection for each one where you really want to be using the same connection throughout all of the calls.
-
ronin-37814 (at lighthouseapp) March 11th, 2009 @ 11:06 PM
- Title changed from Adding cleanup_connection method to Modifying with_connection method
I've moved the functionality to with_connection per Koz's suggestion.
If a connection exists with_connection will simply yield the connection. If a connection doesn't exist with_connection will call connection which will checkout a connection and set it as the current connection, yield it, and ensure it's checked in after the block finishes.
This ensures that any nested with_connection calls won't check out multiple connections.
... And it doesn't increase the # of lines of the with_connection method :)
-
Pratik March 12th, 2009 @ 12:34 AM
- Assigned user changed from Pratik to Michael Koziarski
-
ronin-37814 (at lighthouseapp) April 29th, 2009 @ 04:50 AM
So what's the deal? Do you have any response Koz?
-
Repository May 1st, 2009 @ 02:58 PM
- State changed from new to resolved
(from [5501b99a19a2a67a9a920fd3c7bff071a2ecf058]) Ensure ActiveRecord::Base.connection_pool.with_connection creates a new connection only when needed [#1752 state:resolved]
Signed-off-by: Pratik Naik pratiknaik@gmail.com http://github.com/rails/rails/co...
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>
People watching this ticket
Attachments
Tags
Referenced by
- 2149 Inconsistent has_many validation. You didn't completely got my earlier comment, which is un...
- 1752 Modifying with_connection method (from [5501b99a19a2a67a9a920fd3c7bff071a2ecf058]) Ensure ...