Skip to content

Commit 0bdf44d

Browse files
hharenMatthew Draper
andauthored
Raise specific exception when a connection is not defined
Co-authored-by: Matthew Draper <[email protected]>
1 parent 7b1ceb7 commit 0bdf44d

File tree

8 files changed

+86
-21
lines changed

8 files changed

+86
-21
lines changed

activerecord/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* Raise specific exception when a connection is not defined.
2+
3+
The new `ConnectionNotDefined` exception provides connection name, shard and role accessors indicating the details of the connection that was requested.
4+
5+
*Hana Harencarova*, *Matthew Draper*
6+
17
* Delete the deprecated constant `ActiveRecord::ImmutableRelation`.
28

39
*Xavier Noria*

activerecord/lib/active_record/connection_adapters/abstract/connection_handler.rb

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -210,18 +210,25 @@ def remove_connection_pool(connection_name, role: ActiveRecord::Base.current_rol
210210
# This makes retrieving the connection pool O(1) once the process is warm.
211211
# When a connection is established or removed, we invalidate the cache.
212212
def retrieve_connection_pool(connection_name, role: ActiveRecord::Base.current_role, shard: ActiveRecord::Base.current_shard, strict: false)
213-
pool = get_pool_manager(connection_name)&.get_pool_config(role, shard)&.pool
213+
pool_manager = get_pool_manager(connection_name)
214+
pool = pool_manager&.get_pool_config(role, shard)&.pool
214215

215216
if strict && !pool
216-
if shard != ActiveRecord::Base.default_shard
217-
message = "No connection pool for '#{connection_name}' found for the '#{shard}' shard."
218-
elsif role != ActiveRecord::Base.default_role
219-
message = "No connection pool for '#{connection_name}' found for the '#{role}' role."
220-
else
221-
message = "No connection pool for '#{connection_name}' found."
222-
end
217+
selector = [
218+
("'#{shard}' shard" unless shard == ActiveRecord::Base.default_shard),
219+
("'#{role}' role" unless role == ActiveRecord::Base.default_role),
220+
].compact.join(" and ")
221+
222+
selector = [
223+
(connection_name unless connection_name == "ActiveRecord::Base"),
224+
selector.presence,
225+
].compact.join(" with ")
226+
227+
selector = " for #{selector}" if selector.present?
228+
229+
message = "No database connection defined#{selector}."
223230

224-
raise ConnectionNotEstablished, message
231+
raise ConnectionNotDefined.new(message, connection_name: connection_name, shard: shard, role: role)
225232
end
226233

227234
pool

activerecord/lib/active_record/connection_adapters/abstract_adapter.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,8 @@ def verified!
10441044
end
10451045

10461046
def retryable_connection_error?(exception)
1047-
exception.is_a?(ConnectionNotEstablished) || exception.is_a?(ConnectionFailed)
1047+
(exception.is_a?(ConnectionNotEstablished) && !exception.is_a?(ConnectionNotDefined)) ||
1048+
exception.is_a?(ConnectionFailed)
10481049
end
10491050

10501051
def invalidate_transaction(exception)

activerecord/lib/active_record/errors.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,19 @@ def set_pool(connection_pool)
8484
class ConnectionTimeoutError < ConnectionNotEstablished
8585
end
8686

87+
# Raised when a database connection pool is requested but
88+
# has not been defined.
89+
class ConnectionNotDefined < ConnectionNotEstablished
90+
def initialize(message = nil, connection_name: nil, role: nil, shard: nil)
91+
super(message)
92+
@connection_name = connection_name
93+
@role = role
94+
@shard = shard
95+
end
96+
97+
attr_reader :connection_name, :role, :shard
98+
end
99+
87100
# Raised when connection to the database could not been established because it was not
88101
# able to connect to the host or when the authorization failed.
89102
class DatabaseConnectionError < ConnectionNotEstablished

activerecord/test/cases/connection_adapters/connection_handlers_multi_db_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,13 @@ def test_retrieve_connection_pool_with_invalid_id
359359
end
360360

361361
def test_calling_connected_to_on_a_non_existent_handler_raises
362-
error = assert_raises ActiveRecord::ConnectionNotEstablished do
362+
error = assert_raises ActiveRecord::ConnectionNotDefined do
363363
ActiveRecord::Base.connected_to(role: :non_existent) do
364364
Person.first
365365
end
366366
end
367367

368-
assert_equal "No connection pool for 'ActiveRecord::Base' found for the 'non_existent' role.", error.message
368+
assert_equal "No database connection defined for 'non_existent' role.", error.message
369369
end
370370

371371
def test_default_handlers_are_writing_and_reading

activerecord/test/cases/connection_adapters/connection_handlers_sharding_db_test.rb

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def test_establishing_a_connection_in_connected_to_block_uses_current_role_and_s
2121
ActiveRecord::Base.establish_connection(db_config)
2222
assert_nothing_raised { Person.first }
2323

24-
assert_equal [:default, :shard_one], ActiveRecord::Base.connection_handler.send(:get_pool_manager, "ActiveRecord::Base").shard_names
24+
assert_equal [:default, :shard_one].sort, ActiveRecord::Base.connection_handler.send(:get_pool_manager, "ActiveRecord::Base").shard_names.sort
2525
end
2626
end
2727

@@ -233,13 +233,51 @@ def test_calling_connected_to_on_a_non_existent_shard_raises
233233
default: { writing: :arunit, reading: :arunit }
234234
})
235235

236-
error = assert_raises ActiveRecord::ConnectionNotEstablished do
236+
error = assert_raises ActiveRecord::ConnectionNotDefined do
237237
ActiveRecord::Base.connected_to(role: :reading, shard: :foo) do
238238
Person.first
239239
end
240240
end
241241

242-
assert_equal "No connection pool for 'ActiveRecord::Base' found for the 'foo' shard.", error.message
242+
assert_equal "No database connection defined for 'foo' shard and 'reading' role.", error.message
243+
assert_equal "ActiveRecord::Base", error.connection_name
244+
assert_equal :foo, error.shard
245+
assert_equal :reading, error.role
246+
end
247+
248+
def test_calling_connected_to_on_a_non_existent_role_for_shard_raises
249+
ActiveRecord::Base.connects_to(shards: {
250+
default: { writing: :arunit, reading: :arunit },
251+
shard_one: { writing: :arunit, reading: :arunit }
252+
})
253+
254+
error = assert_raises ActiveRecord::ConnectionNotDefined do
255+
ActiveRecord::Base.connected_to(role: :non_existent, shard: :shard_one) do
256+
Person.first
257+
end
258+
end
259+
260+
assert_equal "No database connection defined for 'shard_one' shard and 'non_existent' role.", error.message
261+
assert_equal "ActiveRecord::Base", error.connection_name
262+
assert_equal :shard_one, error.shard
263+
assert_equal :non_existent, error.role
264+
end
265+
266+
def test_calling_connected_to_on_a_default_role_for_non_existent_shard_raises
267+
ActiveRecord::Base.connects_to(shards: {
268+
default: { writing: :arunit, reading: :arunit }
269+
})
270+
271+
error = assert_raises ActiveRecord::ConnectionNotDefined do
272+
ActiveRecord::Base.connected_to(shard: :foo) do
273+
Person.first
274+
end
275+
end
276+
277+
assert_equal "No database connection defined for 'foo' shard.", error.message
278+
assert_equal "ActiveRecord::Base", error.connection_name
279+
assert_equal :foo, error.shard
280+
assert_equal :writing, error.role
243281
end
244282

245283
def test_cannot_swap_shards_while_prohibited

activerecord/test/cases/fixtures_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,7 @@ def test_only_existing_connections_are_replaced
17101710

17111711
setup_shared_connection_pool
17121712

1713-
assert_raises(ActiveRecord::ConnectionNotEstablished) do
1713+
assert_raises(ActiveRecord::ConnectionNotDefined) do
17141714
ActiveRecord::Base.connected_to(role: :reading, shard: :two) do
17151715
ActiveRecord::Base.retrieve_connection
17161716
end
@@ -1721,7 +1721,7 @@ def test_only_existing_connections_are_restored
17211721
clean_up_connection_handler
17221722
teardown_shared_connection_pool
17231723

1724-
assert_raises(ActiveRecord::ConnectionNotEstablished) do
1724+
assert_raises(ActiveRecord::ConnectionNotDefined) do
17251725
ActiveRecord::Base.connected_to(role: :reading) do
17261726
ActiveRecord::Base.retrieve_connection
17271727
end

activerecord/test/cases/unconnected_test.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,21 @@ def setup
2323
end
2424

2525
def test_connection_no_longer_established
26-
assert_raise(ActiveRecord::ConnectionNotEstablished) do
26+
assert_raise(ActiveRecord::ConnectionNotDefined) do
2727
TestRecord.find(1)
2828
end
2929

30-
assert_raise(ActiveRecord::ConnectionNotEstablished) do
30+
assert_raise(ActiveRecord::ConnectionNotDefined) do
3131
TestRecord.new.save
3232
end
3333
end
3434

3535
def test_error_message_when_connection_not_established
36-
error = assert_raise(ActiveRecord::ConnectionNotEstablished) do
36+
error = assert_raise(ActiveRecord::ConnectionNotDefined) do
3737
TestRecord.find(1)
3838
end
3939

40-
assert_equal "No connection pool for 'ActiveRecord::Base' found.", error.message
40+
assert_equal "No database connection defined.", error.message
4141
end
4242

4343
def test_underlying_adapter_no_longer_active

0 commit comments

Comments
 (0)