Make PostgreSQL failover work with distributed cache.

This commit is contained in:
Guo Xiang Tan 2017-10-20 16:39:31 +08:00
parent 989280a222
commit fe1e78ddf4
4 changed files with 20 additions and 8 deletions

View File

@ -7,10 +7,12 @@ class PostgreSQLFallbackHandler
include Singleton include Singleton
attr_reader :masters_down attr_reader :masters_down
attr_accessor :initialized
def initialize def initialize
@masters_down = DistributedCache.new('masters_down') @masters_down = DistributedCache.new('masters_down', namespace: false)
@mutex = Mutex.new @mutex = Mutex.new
@initialized = false
end end
def verify_master def verify_master
@ -126,13 +128,12 @@ module ActiveRecord
else else
begin begin
connection = postgresql_connection(config) connection = postgresql_connection(config)
fallback_handler.master_down = false fallback_handler.initialized ||= true
rescue PG::ConnectionBad => e rescue PG::ConnectionBad => e
on_boot = fallback_handler.master_down?.nil?
fallback_handler.master_down = true fallback_handler.master_down = true
fallback_handler.verify_master fallback_handler.verify_master
if on_boot if !fallback_handler.initialized
return postgresql_fallback_connection(config) return postgresql_fallback_connection(config)
else else
raise e raise e

View File

@ -105,10 +105,11 @@ class DistributedCache
attr_reader :key attr_reader :key
def initialize(key, manager = nil) def initialize(key, manager: nil, namespace: true)
@key = key @key = key
@data = {} @data = {}
@manager = manager || DistributedCache.default_manager @manager = manager || DistributedCache.default_manager
@namespace = namespace
@manager.ensure_subscribe! @manager.ensure_subscribe!
@manager.register(self) @manager.register(self)
@ -142,7 +143,14 @@ class DistributedCache
end end
def hash(db = nil) def hash(db = nil)
db ||= RailsMultisite::ConnectionManagement.current_db db ||= begin
if @namespace
RailsMultisite::ConnectionManagement.current_db
else
RailsMultisite::ConnectionManagement::DEFAULT
end
end
@data[db] ||= ThreadSafe::Hash.new @data[db] ||= ThreadSafe::Hash.new
end end

View File

@ -62,6 +62,7 @@ describe ActiveRecord::ConnectionHandling do
it 'should failover to a replica server' do it 'should failover to a replica server' do
RailsMultisite::ConnectionManagement.stubs(:all_dbs).returns(['default', multisite_db]) RailsMultisite::ConnectionManagement.stubs(:all_dbs).returns(['default', multisite_db])
postgresql_fallback_handler.expects(:verify_master).at_least(3)
[config, multisite_config].each do |configuration| [config, multisite_config].each do |configuration|
ActiveRecord::Base.expects(:postgresql_connection).with(configuration).raises(PG::ConnectionBad) ActiveRecord::Base.expects(:postgresql_connection).with(configuration).raises(PG::ConnectionBad)
@ -113,13 +114,15 @@ describe ActiveRecord::ConnectionHandling do
context 'when both master and replica server is down' do context 'when both master and replica server is down' do
it 'should raise the right error' do it 'should raise the right error' do
ActiveRecord::Base.expects(:postgresql_connection).with(config).raises(PG::ConnectionBad).once ActiveRecord::Base.expects(:postgresql_connection).with(config).raises(PG::ConnectionBad)
ActiveRecord::Base.expects(:postgresql_connection).with(config.dup.merge( ActiveRecord::Base.expects(:postgresql_connection).with(config.dup.merge(
host: replica_host, host: replica_host,
port: replica_port port: replica_port
)).raises(PG::ConnectionBad).once )).raises(PG::ConnectionBad).once
postgresql_fallback_handler.expects(:verify_master).twice
2.times do 2.times do
expect { ActiveRecord::Base.postgresql_fallback_connection(config) } expect { ActiveRecord::Base.postgresql_fallback_connection(config) }
.to raise_error(PG::ConnectionBad) .to raise_error(PG::ConnectionBad)

View File

@ -14,7 +14,7 @@ describe DistributedCache do
end end
def cache(name) def cache(name)
DistributedCache.new(name, @manager) DistributedCache.new(name, manager: @manager)
end end
let! :cache1 do let! :cache1 do