Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Modifying with_connection method

#1752

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

Reported by ronin-37814 (at lighthouseapp) · January 13th, 2009 @ 10:36 PM

State: resolved
Milestone: 2.x
Assigned to: Michael Koziarski Michael Koziarski
Importance: none

Activity

  1. Pratik
    Pratik
    • 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

    January 13th, 2009 @ 11:03 PM

  2. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    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.

    January 14th, 2009 @ 06:29 AM

  3. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)
    • 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.

    January 14th, 2009 @ 07:58 PM

  4. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    added more real-world test case for nesting safety

    January 14th, 2009 @ 10:03 PM

  5. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    renamed thread local variable to cleanup_connection

    January 14th, 2009 @ 10:05 PM

  6. hosiawak
  7. Michael Lang
    Michael Lang

    +1

    This patch lets me use ActiveRecord in Ramaze. A most timely patch.

    February 4th, 2009 @ 05:35 AM

  8. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    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.

    February 17th, 2009 @ 09:31 PM

  9. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    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.

    February 17th, 2009 @ 10:25 PM

  10. Nick Sieger
    Nick Sieger

    I can appreciate the desire for this patch, but what about just piggy-backing off the existing connection method instead? Consider this patch:

    http://gist.github.com/66038

    It's just a proof-of-concept, may need some cleaning up and adding tests/merging w/ coderrr's patch.

    What do you think?

    February 17th, 2009 @ 10:48 PM

  11. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    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.

    February 17th, 2009 @ 11:01 PM

  12. Nick Sieger
    Nick Sieger

    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?

    February 18th, 2009 @ 01:48 AM

  13. Nick Sieger
    Nick Sieger

    Here's a patch w/ coderrr's tests and my approach with passing the block down through AR::Base.connection.

    February 18th, 2009 @ 08:28 PM

  14. Michael Koziarski
    Michael Koziarski

    Don't we already have a with_connection method on the connection pool?

    Perhaps we just make that available from AR::Base more simply?

    February 18th, 2009 @ 08:52 PM

  15. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    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

    February 18th, 2009 @ 08:55 PM

  16. Dan Pickett
  17. Nick Sieger
    Nick Sieger

    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.

    February 19th, 2009 @ 05:04 PM

  18. Michael Koziarski
    Michael Koziarski

    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?

    February 19th, 2009 @ 07:01 PM

  19. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    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.

    February 19th, 2009 @ 07:10 PM

  20. Jacob Burkhart
    Jacob Burkhart

    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.

    February 26th, 2009 @ 04:01 PM

  21. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    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.

    February 26th, 2009 @ 04:08 PM

  22. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)
    • 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 :)

    March 11th, 2009 @ 11:06 PM

  23. Pratik
    Pratik
    • Assigned user changed from Pratik to Michael Koziarski

    March 12th, 2009 @ 12:34 AM

  24. ronin-37814 (at lighthouseapp)
    ronin-37814 (at lighthouseapp)

    So what's the deal? Do you have any response Koz?

    April 29th, 2009 @ 04:50 AM

  25. Repository
    Repository
    • State changed from new to resolved

    (from [5501b99a19a2a67a9a920fd3c7bff071a2ecf058]) Ensure ActiveRecord::Base.connection_pool.with_connection creates a new connection only when needed [#1752 Modifying with_connection method state:resolved]

    Signed-off-by: Pratik Naik pratiknaik@gmail.com http://github.com/rails/rails/co...

    May 1st, 2009 @ 02:58 PM