mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Revert "Disable automatic write protection on replicas"
This reverts commit 951deecc52
.
This change prevents applications from testing replicas and would
require explicitly setting `prevent_writes` when connecting to reading
roles in `connected_to`. For now we'll revert this until there's a
longer term fix in place
This commit is contained in:
parent
6ae78e964d
commit
69bc201929
11 changed files with 34 additions and 38 deletions
|
@ -16,19 +16,6 @@
|
|||
|
||||
*Jorge Manrubia*
|
||||
|
||||
* Disable automatic write protection on replicas.
|
||||
|
||||
Write protection is no longer automatically enabled for replicas.
|
||||
You can manually prevent writes in your app with
|
||||
`while_preventing_writes`. To automatically disable all writes on
|
||||
your replica, configure the database user you are using to connect
|
||||
to your replica to prevent writes. How you configure this is
|
||||
specific to which database adapter you are using, but it usually
|
||||
involves only granting the database user permission to do `SELECT`
|
||||
queries.
|
||||
|
||||
*Adam Hess*
|
||||
|
||||
* The MySQL adapter now cast numbers and booleans bind parameters to to string for safety reasons.
|
||||
|
||||
When comparing a string and a number in a query, MySQL convert the string to a number. So for
|
||||
|
|
|
@ -131,12 +131,15 @@ module ActiveRecord
|
|||
|
||||
# Determines whether writes are currently being prevented.
|
||||
#
|
||||
# Returns true if the connection is a replica.
|
||||
#
|
||||
# If the application is using legacy handling, returns
|
||||
# true if +connection_handler.prevent_writes+ is set.
|
||||
#
|
||||
# If the application is using the new connection handling
|
||||
# will return true based on +current_preventing_writes+.
|
||||
def preventing_writes?
|
||||
return true if replica?
|
||||
return ActiveRecord::Base.connection_handler.prevent_writes if ActiveRecord.legacy_connection_handling
|
||||
return false if connection_klass.nil?
|
||||
|
||||
|
|
|
@ -184,6 +184,8 @@ module ActiveRecord
|
|||
raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
|
||||
end
|
||||
|
||||
prevent_writes = true if role == ActiveRecord.reading_role
|
||||
|
||||
connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes }
|
||||
yield
|
||||
ensure
|
||||
|
@ -202,6 +204,8 @@ module ActiveRecord
|
|||
raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
|
||||
end
|
||||
|
||||
prevent_writes = true if role == ActiveRecord.reading_role
|
||||
|
||||
self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
|
||||
end
|
||||
|
||||
|
@ -352,6 +356,8 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def with_role_and_shard(role, shard, prevent_writes)
|
||||
prevent_writes = true if role == ActiveRecord.reading_role
|
||||
|
||||
if ActiveRecord.legacy_connection_handling
|
||||
with_handler(role.to_sym) do
|
||||
connection_handler.while_preventing_writes(prevent_writes) do
|
||||
|
|
|
@ -58,7 +58,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
def read_from_replica(&blk)
|
||||
ActiveRecord::Base.connected_to(role: ActiveRecord.reading_role) do
|
||||
ActiveRecord::Base.connected_to(role: ActiveRecord.reading_role, prevent_writes: true) do
|
||||
instrumenter.instrument("database_selector.active_record.read_from_replica") do
|
||||
yield
|
||||
end
|
||||
|
|
|
@ -1721,7 +1721,7 @@ class BasicsTest < ActiveRecord::TestCase
|
|||
SecondAbstractClass.connecting_to(role: :reading)
|
||||
|
||||
assert SecondAbstractClass.connected_to?(role: :reading)
|
||||
assert_not SecondAbstractClass.current_preventing_writes
|
||||
assert SecondAbstractClass.current_preventing_writes
|
||||
ensure
|
||||
ActiveRecord::Base.connected_to_stack.pop
|
||||
end
|
||||
|
@ -1777,24 +1777,24 @@ class BasicsTest < ActiveRecord::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
test "#connected_to_many does not sets prevent_writes if role is reading" do
|
||||
test "#connected_to_many sets prevent_writes if role is reading" do
|
||||
ActiveRecord::Base.connected_to_many([SecondAbstractClass], role: :reading) do
|
||||
assert_not SecondAbstractClass.current_preventing_writes
|
||||
assert SecondAbstractClass.current_preventing_writes
|
||||
assert_not ActiveRecord::Base.current_preventing_writes
|
||||
end
|
||||
end
|
||||
|
||||
test "#connected_to_many with a single argument for classes does not set prevent_writes" do
|
||||
test "#connected_to_many with a single argument for classes" do
|
||||
ActiveRecord::Base.connected_to_many(SecondAbstractClass, role: :reading) do
|
||||
assert_not SecondAbstractClass.current_preventing_writes
|
||||
assert SecondAbstractClass.current_preventing_writes
|
||||
assert_not ActiveRecord::Base.current_preventing_writes
|
||||
end
|
||||
end
|
||||
|
||||
test "#connected_to_many with a multiple classes without brackets does not prevent_writes" do
|
||||
test "#connected_to_many with a multiple classes without brackets works" do
|
||||
ActiveRecord::Base.connected_to_many(FirstAbstractClass, SecondAbstractClass, role: :reading) do
|
||||
assert_not FirstAbstractClass.current_preventing_writes
|
||||
assert_not SecondAbstractClass.current_preventing_writes
|
||||
assert FirstAbstractClass.current_preventing_writes
|
||||
assert SecondAbstractClass.current_preventing_writes
|
||||
assert_not ActiveRecord::Base.current_preventing_writes
|
||||
end
|
||||
end
|
||||
|
|
|
@ -130,7 +130,7 @@ module ActiveRecord
|
|||
assert_equal :reading, ActiveRecord::Base.current_role
|
||||
assert ActiveRecord::Base.connected_to?(role: :reading)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :writing)
|
||||
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connected_to(role: :writing) do
|
||||
|
|
|
@ -135,7 +135,7 @@ module ActiveRecord
|
|||
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
|
||||
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connected_to(role: :writing, shard: :default) do
|
||||
|
@ -153,7 +153,7 @@ module ActiveRecord
|
|||
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
|
||||
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connected_to(role: :writing, shard: :shard_one) do
|
||||
|
|
|
@ -391,23 +391,23 @@ module ActiveRecord
|
|||
|
||||
# Switch only primary to reading
|
||||
PrimaryBase.connected_to(role: :reading) do
|
||||
assert_not_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_not_predicate SecondaryBase.connection, :preventing_writes?
|
||||
|
||||
# Switch global to reading
|
||||
ActiveRecord::Base.connected_to(role: :reading) do
|
||||
assert_not_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_not_predicate SecondaryBase.connection, :preventing_writes?
|
||||
assert_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_predicate SecondaryBase.connection, :preventing_writes?
|
||||
|
||||
# Switch only secondary to writing
|
||||
SecondaryBase.connected_to(role: :writing) do
|
||||
assert_not_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_not_predicate SecondaryBase.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
# Ensure restored to global reading
|
||||
assert_not_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_not_predicate SecondaryBase.connection, :preventing_writes?
|
||||
assert_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_predicate SecondaryBase.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
# Switch everything to writing
|
||||
|
@ -416,7 +416,7 @@ module ActiveRecord
|
|||
assert_not_predicate SecondaryBase.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
assert_not_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_predicate PrimaryBase.connection, :preventing_writes?
|
||||
assert_not_predicate SecondaryBase.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
|
@ -444,7 +444,7 @@ module ActiveRecord
|
|||
assert_not_predicate ApplicationRecord.connection, :preventing_writes?
|
||||
|
||||
ApplicationRecord.connected_to(role: :reading) do
|
||||
assert_not_predicate ApplicationRecord.connection, :preventing_writes?
|
||||
assert_predicate ApplicationRecord.connection, :preventing_writes?
|
||||
end
|
||||
end
|
||||
ensure
|
||||
|
|
|
@ -180,7 +180,7 @@ module ActiveRecord
|
|||
assert_equal :reading, ActiveRecord::Base.current_role
|
||||
assert ActiveRecord::Base.connected_to?(role: :reading)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :writing)
|
||||
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connected_to(role: :writing) do
|
||||
|
|
|
@ -150,7 +150,7 @@ module ActiveRecord
|
|||
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :shard_one)
|
||||
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connected_to(role: :writing, shard: :default) do
|
||||
|
@ -172,7 +172,7 @@ module ActiveRecord
|
|||
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :shard_one)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :writing, shard: :default)
|
||||
assert_not ActiveRecord::Base.connected_to?(role: :reading, shard: :default)
|
||||
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
end
|
||||
|
||||
ActiveRecord::Base.connected_to(role: :writing, shard: :shard_one) do
|
||||
|
|
|
@ -62,7 +62,7 @@ module ActiveRecord
|
|||
called = true
|
||||
|
||||
assert ActiveRecord::Base.connected_to?(role: :reading)
|
||||
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
|
||||
ActiveRecord::Base.connected_to(role: :writing, prevent_writes: false) do
|
||||
assert ActiveRecord::Base.connected_to?(role: :writing)
|
||||
|
@ -70,7 +70,7 @@ module ActiveRecord
|
|||
end
|
||||
|
||||
assert ActiveRecord::Base.connected_to?(role: :reading)
|
||||
assert_not_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
assert_predicate ActiveRecord::Base.connection, :preventing_writes?
|
||||
end
|
||||
assert called
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue