mirror of https://github.com/rails/rails
Merge pull request #39758 from tgxworld/create_own_connection_handler_for_advisory_locks
Move advisory locks to own connection handler.
This commit is contained in:
commit
8de10f9bb6
|
@ -36,7 +36,6 @@ require "active_record/errors"
|
|||
module ActiveRecord
|
||||
extend ActiveSupport::Autoload
|
||||
|
||||
autoload :AdvisoryLockBase
|
||||
autoload :Base
|
||||
autoload :Callbacks
|
||||
autoload :Core
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ActiveRecord
|
||||
# This class is used to create a connection that we can use for advisory
|
||||
# locks. This will take out a "global" lock that can't be accidentally
|
||||
# removed if a new connection is established during a migration.
|
||||
class AdvisoryLockBase < ActiveRecord::Base # :nodoc:
|
||||
self.abstract_class = true
|
||||
|
||||
self.connection_specification_name = "AdvisoryLockBase"
|
||||
|
||||
class << self
|
||||
def _internal?
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1376,20 +1376,29 @@ module ActiveRecord
|
|||
|
||||
def with_advisory_lock
|
||||
lock_id = generate_migrator_advisory_lock_id
|
||||
AdvisoryLockBase.establish_connection(ActiveRecord::Base.connection_db_config) unless AdvisoryLockBase.connected?
|
||||
connection = AdvisoryLockBase.connection
|
||||
got_lock = connection.get_advisory_lock(lock_id)
|
||||
raise ConcurrentMigrationError unless got_lock
|
||||
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
||||
yield
|
||||
ensure
|
||||
if got_lock && !connection.release_advisory_lock(lock_id)
|
||||
raise ConcurrentMigrationError.new(
|
||||
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
||||
)
|
||||
|
||||
with_advisory_lock_connection do |connection|
|
||||
got_lock = connection.get_advisory_lock(lock_id)
|
||||
raise ConcurrentMigrationError unless got_lock
|
||||
load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
|
||||
yield
|
||||
ensure
|
||||
if got_lock && !connection.release_advisory_lock(lock_id)
|
||||
raise ConcurrentMigrationError.new(
|
||||
ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def with_advisory_lock_connection
|
||||
pool = ActiveRecord::ConnectionAdapters::ConnectionHandler.new.establish_connection(
|
||||
ActiveRecord::Base.connection_db_config
|
||||
)
|
||||
|
||||
pool.with_connection { |connection| yield(connection) }
|
||||
end
|
||||
|
||||
MIGRATOR_SALT = 2053462845
|
||||
def generate_migrator_advisory_lock_id
|
||||
db_name_hash = Zlib.crc32(Base.connection.current_database)
|
||||
|
|
|
@ -940,8 +940,10 @@ class MigrationTest < ActiveRecord::TestCase
|
|||
|
||||
e = assert_raises(ActiveRecord::ConcurrentMigrationError) do
|
||||
silence_stream($stderr) do
|
||||
migrator.send(:with_advisory_lock) do
|
||||
ActiveRecord::AdvisoryLockBase.connection.release_advisory_lock(lock_id)
|
||||
migrator.stub(:with_advisory_lock_connection, ->(&block) { block.call(ActiveRecord::Base.connection) }) do
|
||||
migrator.send(:with_advisory_lock) do
|
||||
ActiveRecord::Base.connection.release_advisory_lock(lock_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue