diff options
author | Eileen Uchitelle <eileencodes@gmail.com> | 2018-11-20 13:57:25 -0500 |
---|---|---|
committer | Eileen Uchitelle <eileencodes@gmail.com> | 2018-11-20 16:02:40 -0500 |
commit | 5ce3e022ef136324d288fb493e0938e76a74981a (patch) | |
tree | 5f27b53bc3068cc12765d2df7969ec3f3594cd24 /activerecord | |
parent | 023a840f5f10c5a611a0618ff8ea9e16cd771f93 (diff) | |
download | rails-5ce3e022ef136324d288fb493e0938e76a74981a.tar.gz rails-5ce3e022ef136324d288fb493e0938e76a74981a.tar.bz2 rails-5ce3e022ef136324d288fb493e0938e76a74981a.zip |
Make connection handler per thread instead of per fiber
The connection handler was using the RuntimeRegistry which kind of
implies it's a per thread registry. But it's actually per fiber.
If you have an application that uses fibers and you're using multiple
databases, when you switch the connection handler to swap connections
new fibers running on the same thread used to get a different connection
id. This PR changes the code to actually use a thread so that we get
the same connection.
Fixes https://github.com/rails/rails/issues/30047
[Eileen M. Uchitelle, Aaron Patterson, & Arthur Neeves]
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/lib/active_record/core.rb | 4 | ||||
-rw-r--r-- | activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb | 37 |
2 files changed, 39 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/core.rb b/activerecord/lib/active_record/core.rb index 50f3087c51..8f4d292a4b 100644 --- a/activerecord/lib/active_record/core.rb +++ b/activerecord/lib/active_record/core.rb @@ -129,11 +129,11 @@ module ActiveRecord self.filter_attributes = [] def self.connection_handler - ActiveRecord::RuntimeRegistry.connection_handler || default_connection_handler + Thread.current.thread_variable_get("ar_connection_handler") || default_connection_handler end def self.connection_handler=(handler) - ActiveRecord::RuntimeRegistry.connection_handler = handler + Thread.current.thread_variable_set("ar_connection_handler", handler) end self.default_connection_handler = ConnectionAdapters::ConnectionHandler.new diff --git a/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb b/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb index a394430dfe..393b577c1d 100644 --- a/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb +++ b/activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb @@ -280,6 +280,43 @@ module ActiveRecord assert_nil @rw_handler.retrieve_connection_pool("foo") assert_nil @ro_handler.retrieve_connection_pool("foo") end + + def test_connection_handlers_are_per_thread_and_not_per_fiber + original_handlers = ActiveRecord::Base.connection_handlers + + ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler, reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new } + + reading_handler = ActiveRecord::Base.connection_handlers[:reading] + + reading = ActiveRecord::Base.with_handler(:reading) do + Person.connection_handler + end + + assert_not_equal reading, ActiveRecord::Base.connection_handler + assert_equal reading, reading_handler + ensure + ActiveRecord::Base.connection_handlers = original_handlers + end + + def test_connection_handlers_swapping_connections_in_fiber + original_handlers = ActiveRecord::Base.connection_handlers + + ActiveRecord::Base.connection_handlers = { writing: ActiveRecord::Base.default_connection_handler, reading: ActiveRecord::ConnectionAdapters::ConnectionHandler.new } + + reading_handler = ActiveRecord::Base.connection_handlers[:reading] + + enum = Enumerator.new do |r| + r << ActiveRecord::Base.connection_handler + end + + reading = ActiveRecord::Base.with_handler(:reading) do + enum.next + end + + assert_equal reading, reading_handler + ensure + ActiveRecord::Base.connection_handlers = original_handlers + end end end end |