mirror of https://github.com/rails/rails
Raise specific exception when a connection is not defined
Co-authored-by: Matthew Draper <matthewd@github.com>
This commit is contained in:
parent
7b1ceb7659
commit
0bdf44d921
|
@ -1,3 +1,9 @@
|
|||
* Raise specific exception when a connection is not defined.
|
||||
|
||||
The new `ConnectionNotDefined` exception provides connection name, shard and role accessors indicating the details of the connection that was requested.
|
||||
|
||||
*Hana Harencarova*, *Matthew Draper*
|
||||
|
||||
* Delete the deprecated constant `ActiveRecord::ImmutableRelation`.
|
||||
|
||||
*Xavier Noria*
|
||||
|
|
|
@ -210,18 +210,25 @@ module ActiveRecord
|
|||
# This makes retrieving the connection pool O(1) once the process is warm.
|
||||
# When a connection is established or removed, we invalidate the cache.
|
||||
def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, strict: false)
|
||||
pool = get_pool_manager(connection_name)&.get_pool_config(role, shard)&.pool
|
||||
pool_manager = get_pool_manager(connection_name)
|
||||
pool = pool_manager&.get_pool_config(role, shard)&.pool
|
||||
|
||||
if strict && !pool
|
||||
if shard != ActiveRecord::Base.default_shard
|
||||
message = "No connection pool for '#{connection_name}' found for the '#{shard}' shard."
|
||||
elsif role != ActiveRecord::Base.default_role
|
||||
message = "No connection pool for '#{connection_name}' found for the '#{role}' role."
|
||||
else
|
||||
message = "No connection pool for '#{connection_name}' found."
|
||||
end
|
||||
selector = [
|
||||
("'#{shard}' shard" unless shard == ActiveRecord::Base.default_shard),
|
||||
("'#{role}' role" unless role == ActiveRecord::Base.default_role),
|
||||
].compact.join(" and ")
|
||||
|
||||
raise ConnectionNotEstablished, message
|
||||
selector = [
|
||||
(connection_name unless connection_name == "ActiveRecord::Base"),
|
||||
selector.presence,
|
||||
].compact.join(" with ")
|
||||
|
||||
selector = " for #{selector}" if selector.present?
|
||||
|
||||
message = "No database connection defined#{selector}."
|
||||
|
||||
raise ConnectionNotDefined.new(message, connection_name: connection_name, shard: shard, role: role)
|
||||
end
|
||||
|
||||
pool
|
||||
|
|
|
@ -1044,7 +1044,8 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def retryable_connection_error?(exception)
|
||||
exception.is_a?(ConnectionNotEstablished) || exception.is_a?(ConnectionFailed)
|
||||
(exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
|
||||
exception.is_a?(ConnectionFailed)
|
||||
end
|
||||
|
||||
def invalidate_transaction(exception)
|
||||
|
|
|
@ -84,6 +84,19 @@ module ActiveRecord
|
|||
class ConnectionTimeoutError < ConnectionNotEstablished
|
||||
end
|
||||
|
||||
# Raised when a database connection pool is requested but
|
||||
# has not been defined.
|
||||
class ConnectionNotDefined < ConnectionNotEstablished
|
||||
def initialize(message = nil, connection_name: nil, role: nil, shard: nil)
|
||||
super(message)
|
||||
@connection_name = connection_name
|
||||
@role = role
|
||||
@shard = shard
|
||||
end
|
||||
|
||||
attr_reader :connection_name, :role, :shard
|
||||
end
|
||||
|
||||
# Raised when connection to the database could not been established because it was not
|
||||
# able to connect to the host or when the authorization failed.
|
||||
class DatabaseConnectionError < ConnectionNotEstablished
|
||||
|
|
|
@ -359,13 +359,13 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def test_calling_connected_to_on_a_non_existent_handler_raises
|
||||
error = assert_raises ActiveRecord::ConnectionNotEstablished do
|
||||
error = assert_raises ActiveRecord::ConnectionNotDefined do
|
||||
ActiveRecord::Base.connected_to(role: :non_existent) do
|
||||
Person.first
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal "No connection pool for 'ActiveRecord::Base' found for the 'non_existent' role.", error.message
|
||||
assert_equal "No database connection defined for 'non_existent' role.", error.message
|
||||
end
|
||||
|
||||
def test_default_handlers_are_writing_and_reading
|
||||
|
|
|
@ -21,7 +21,7 @@ module ActiveRecord
|
|||
ActiveRecord::Base.establish_connection(db_config)
|
||||
assert_nothing_raised { Person.first }
|
||||
|
||||
assert_equal [:default, :shard_one], ActiveRecord::Base.connection_handler.send(:get_pool_manager, "ActiveRecord::Base").shard_names
|
||||
assert_equal [:default, :shard_one].sort, ActiveRecord::Base.connection_handler.send(:get_pool_manager, "ActiveRecord::Base").shard_names.sort
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -233,13 +233,51 @@ module ActiveRecord
|
|||
default: { writing: :arunit, reading: :arunit }
|
||||
})
|
||||
|
||||
error = assert_raises ActiveRecord::ConnectionNotEstablished do
|
||||
error = assert_raises ActiveRecord::ConnectionNotDefined do
|
||||
ActiveRecord::Base.connected_to(role: :reading, shard: :foo) do
|
||||
Person.first
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal "No connection pool for 'ActiveRecord::Base' found for the 'foo' shard.", error.message
|
||||
assert_equal "No database connection defined for 'foo' shard and 'reading' role.", error.message
|
||||
assert_equal "ActiveRecord::Base", error.connection_name
|
||||
assert_equal :foo, error.shard
|
||||
assert_equal :reading, error.role
|
||||
end
|
||||
|
||||
def test_calling_connected_to_on_a_non_existent_role_for_shard_raises
|
||||
ActiveRecord::Base.connects_to(shards: {
|
||||
default: { writing: :arunit, reading: :arunit },
|
||||
shard_one: { writing: :arunit, reading: :arunit }
|
||||
})
|
||||
|
||||
error = assert_raises ActiveRecord::ConnectionNotDefined do
|
||||
ActiveRecord::Base.connected_to(role: :non_existent, shard: :shard_one) do
|
||||
Person.first
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal "No database connection defined for 'shard_one' shard and 'non_existent' role.", error.message
|
||||
assert_equal "ActiveRecord::Base", error.connection_name
|
||||
assert_equal :shard_one, error.shard
|
||||
assert_equal :non_existent, error.role
|
||||
end
|
||||
|
||||
def test_calling_connected_to_on_a_default_role_for_non_existent_shard_raises
|
||||
ActiveRecord::Base.connects_to(shards: {
|
||||
default: { writing: :arunit, reading: :arunit }
|
||||
})
|
||||
|
||||
error = assert_raises ActiveRecord::ConnectionNotDefined do
|
||||
ActiveRecord::Base.connected_to(shard: :foo) do
|
||||
Person.first
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal "No database connection defined for 'foo' shard.", error.message
|
||||
assert_equal "ActiveRecord::Base", error.connection_name
|
||||
assert_equal :foo, error.shard
|
||||
assert_equal :writing, error.role
|
||||
end
|
||||
|
||||
def test_cannot_swap_shards_while_prohibited
|
||||
|
|
|
@ -1710,7 +1710,7 @@ class MultipleFixtureConnectionsTest < ActiveRecord::TestCase
|
|||
|
||||
setup_shared_connection_pool
|
||||
|
||||
assert_raises(ActiveRecord::ConnectionNotEstablished) do
|
||||
assert_raises(ActiveRecord::ConnectionNotDefined) do
|
||||
ActiveRecord::Base.connected_to(role: :reading, shard: :two) do
|
||||
ActiveRecord::Base.retrieve_connection
|
||||
end
|
||||
|
@ -1721,7 +1721,7 @@ class MultipleFixtureConnectionsTest < ActiveRecord::TestCase
|
|||
clean_up_connection_handler
|
||||
teardown_shared_connection_pool
|
||||
|
||||
assert_raises(ActiveRecord::ConnectionNotEstablished) do
|
||||
assert_raises(ActiveRecord::ConnectionNotDefined) do
|
||||
ActiveRecord::Base.connected_to(role: :reading) do
|
||||
ActiveRecord::Base.retrieve_connection
|
||||
end
|
||||
|
|
|
@ -23,21 +23,21 @@ class TestUnconnectedAdapter < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_connection_no_longer_established
|
||||
assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
||||
assert_raise(ActiveRecord::ConnectionNotDefined) do
|
||||
TestRecord.find(1)
|
||||
end
|
||||
|
||||
assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
||||
assert_raise(ActiveRecord::ConnectionNotDefined) do
|
||||
TestRecord.new.save
|
||||
end
|
||||
end
|
||||
|
||||
def test_error_message_when_connection_not_established
|
||||
error = assert_raise(ActiveRecord::ConnectionNotEstablished) do
|
||||
error = assert_raise(ActiveRecord::ConnectionNotDefined) do
|
||||
TestRecord.find(1)
|
||||
end
|
||||
|
||||
assert_equal "No connection pool for 'ActiveRecord::Base' found.", error.message
|
||||
assert_equal "No database connection defined.", error.message
|
||||
end
|
||||
|
||||
def test_underlying_adapter_no_longer_active
|
||||
|
|
Loading…
Reference in New Issue