FIX: Couldn't boot Discourse app with a readonly postgres.
This commit is contained in:
parent
8185b8cb06
commit
1b5ee0ae72
|
@ -1,6 +1,7 @@
|
||||||
require 'active_record/connection_adapters/abstract_adapter'
|
require 'active_record/connection_adapters/abstract_adapter'
|
||||||
require 'active_record/connection_adapters/postgresql_adapter'
|
require 'active_record/connection_adapters/postgresql_adapter'
|
||||||
require 'discourse'
|
require 'discourse'
|
||||||
|
require 'sidekiq/pausable'
|
||||||
|
|
||||||
class PostgreSQLFallbackHandler
|
class PostgreSQLFallbackHandler
|
||||||
include Singleton
|
include Singleton
|
||||||
|
@ -48,14 +49,15 @@ class PostgreSQLFallbackHandler
|
||||||
begin
|
begin
|
||||||
logger.warn "#{log_prefix}: Checking master server..."
|
logger.warn "#{log_prefix}: Checking master server..."
|
||||||
connection = ActiveRecord::Base.postgresql_connection(config)
|
connection = ActiveRecord::Base.postgresql_connection(config)
|
||||||
|
is_connection_active = connection.active?
|
||||||
|
connection.disconnect!
|
||||||
|
|
||||||
if connection.active?
|
if is_connection_active
|
||||||
connection.disconnect!
|
|
||||||
ActiveRecord::Base.clear_all_connections!
|
|
||||||
logger.warn "#{log_prefix}: Master server is active. Reconnecting..."
|
logger.warn "#{log_prefix}: Master server is active. Reconnecting..."
|
||||||
|
ActiveRecord::Base.clear_active_connections!
|
||||||
|
ActiveRecord::Base.clear_all_connections!
|
||||||
self.master_up(key)
|
self.master_up(key)
|
||||||
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
disable_readonly_mode
|
||||||
Sidekiq.unpause!
|
Sidekiq.unpause!
|
||||||
end
|
end
|
||||||
rescue => e
|
rescue => e
|
||||||
|
@ -68,10 +70,15 @@ class PostgreSQLFallbackHandler
|
||||||
# Use for testing
|
# Use for testing
|
||||||
def setup!
|
def setup!
|
||||||
@masters_down = {}
|
@masters_down = {}
|
||||||
|
disable_readonly_mode
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def disable_readonly_mode
|
||||||
|
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
||||||
|
end
|
||||||
|
|
||||||
def config
|
def config
|
||||||
ActiveRecord::Base.connection_config
|
ActiveRecord::Base.connection_config
|
||||||
end
|
end
|
||||||
|
@ -100,19 +107,30 @@ module ActiveRecord
|
||||||
config = config.symbolize_keys
|
config = config.symbolize_keys
|
||||||
|
|
||||||
if fallback_handler.master_down?
|
if fallback_handler.master_down?
|
||||||
|
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
||||||
fallback_handler.verify_master
|
fallback_handler.verify_master
|
||||||
|
|
||||||
connection = postgresql_connection(config.dup.merge(host: config[:replica_host], port: config[:replica_port]))
|
connection = postgresql_connection(config.dup.merge(
|
||||||
|
host: config[:replica_host],
|
||||||
|
port: config[:replica_port]
|
||||||
|
))
|
||||||
|
|
||||||
verify_replica(connection)
|
verify_replica(connection)
|
||||||
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
now = Time.zone.now
|
||||||
connection = postgresql_connection(config)
|
connection = postgresql_connection(config)
|
||||||
|
fallback_handler.master_down = false
|
||||||
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
|
||||||
raise e
|
|
||||||
|
if on_boot
|
||||||
|
return postgresql_fallback_connection(config)
|
||||||
|
else
|
||||||
|
raise e
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,34 @@ describe ActiveRecord::ConnectionHandling do
|
||||||
let(:replica_port) { 6432 }
|
let(:replica_port) { 6432 }
|
||||||
|
|
||||||
let(:config) do
|
let(:config) do
|
||||||
ActiveRecord::Base.configurations[Rails.env].merge("adapter" => "postgresql_fallback",
|
ActiveRecord::Base.configurations[Rails.env].merge(
|
||||||
"replica_host" => replica_host,
|
"adapter" => "postgresql_fallback",
|
||||||
"replica_port" => replica_port).symbolize_keys!
|
"replica_host" => replica_host,
|
||||||
|
"replica_port" => replica_port
|
||||||
|
).symbolize_keys!
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:multisite_db) { "database_2" }
|
||||||
|
|
||||||
|
let(:multisite_config) do
|
||||||
|
{
|
||||||
|
host: 'localhost1',
|
||||||
|
port: 5432,
|
||||||
|
replica_host: replica_host,
|
||||||
|
replica_port: replica_port
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
let(:postgresql_fallback_handler) { PostgreSQLFallbackHandler.instance }
|
let(:postgresql_fallback_handler) { PostgreSQLFallbackHandler.instance }
|
||||||
|
|
||||||
|
before do
|
||||||
|
['default', multisite_db].each do |db|
|
||||||
|
with_multisite_db(db) do
|
||||||
|
postgresql_fallback_handler.master_down = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
after do
|
after do
|
||||||
postgresql_fallback_handler.setup!
|
postgresql_fallback_handler.setup!
|
||||||
end
|
end
|
||||||
|
@ -24,17 +45,6 @@ describe ActiveRecord::ConnectionHandling do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when master server is down' do
|
context 'when master server is down' do
|
||||||
let(:multisite_db) { "database_2" }
|
|
||||||
|
|
||||||
let(:multisite_config) do
|
|
||||||
{
|
|
||||||
host: 'localhost1',
|
|
||||||
port: 5432,
|
|
||||||
replica_host: replica_host,
|
|
||||||
replica_port: replica_port
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@replica_connection = mock('replica_connection')
|
@replica_connection = mock('replica_connection')
|
||||||
end
|
end
|
||||||
|
@ -59,10 +69,12 @@ describe ActiveRecord::ConnectionHandling do
|
||||||
ActiveRecord::Base.expects(:postgresql_connection).with(configuration).raises(PG::ConnectionBad)
|
ActiveRecord::Base.expects(:postgresql_connection).with(configuration).raises(PG::ConnectionBad)
|
||||||
ActiveRecord::Base.expects(:verify_replica).with(@replica_connection)
|
ActiveRecord::Base.expects(:verify_replica).with(@replica_connection)
|
||||||
|
|
||||||
ActiveRecord::Base.expects(:postgresql_connection).with(configuration.merge(host: replica_host, port: replica_port)).returns(@replica_connection)
|
ActiveRecord::Base.expects(:postgresql_connection).with(configuration.merge(
|
||||||
|
host: replica_host, port: replica_port)
|
||||||
|
).returns(@replica_connection)
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(postgresql_fallback_handler.master_down?).to eq(nil)
|
expect(postgresql_fallback_handler.master_down?).to eq(false)
|
||||||
|
|
||||||
expect { ActiveRecord::Base.postgresql_fallback_connection(config) }
|
expect { ActiveRecord::Base.postgresql_fallback_connection(config) }
|
||||||
.to raise_error(PG::ConnectionBad)
|
.to raise_error(PG::ConnectionBad)
|
||||||
|
@ -74,7 +86,7 @@ describe ActiveRecord::ConnectionHandling do
|
||||||
expect(Sidekiq.paused?).to eq(true)
|
expect(Sidekiq.paused?).to eq(true)
|
||||||
|
|
||||||
with_multisite_db(multisite_db) do
|
with_multisite_db(multisite_db) do
|
||||||
expect(postgresql_fallback_handler.master_down?).to eq(nil)
|
expect(postgresql_fallback_handler.master_down?).to eq(false)
|
||||||
|
|
||||||
expect { ActiveRecord::Base.postgresql_fallback_connection(multisite_config) }
|
expect { ActiveRecord::Base.postgresql_fallback_connection(multisite_config) }
|
||||||
.to raise_error(PG::ConnectionBad)
|
.to raise_error(PG::ConnectionBad)
|
||||||
|
@ -96,7 +108,6 @@ describe ActiveRecord::ConnectionHandling do
|
||||||
expect(Sidekiq.paused?).to eq(false)
|
expect(Sidekiq.paused?).to eq(false)
|
||||||
expect(ActiveRecord::Base.connection_pool.connections.count).to eq(0)
|
expect(ActiveRecord::Base.connection_pool.connections.count).to eq(0)
|
||||||
|
|
||||||
skip("Figuring out why the following keeps failing to obtain a connection on Travis")
|
|
||||||
expect(ActiveRecord::Base.connection)
|
expect(ActiveRecord::Base.connection)
|
||||||
.to be_an_instance_of(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
.to be_an_instance_of(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
|
||||||
end
|
end
|
||||||
|
@ -106,7 +117,10 @@ describe ActiveRecord::ConnectionHandling 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).once
|
||||||
|
|
||||||
ActiveRecord::Base.expects(:postgresql_connection).with(config.dup.merge(host: replica_host, port: replica_port)).raises(PG::ConnectionBad).once
|
ActiveRecord::Base.expects(:postgresql_connection).with(config.dup.merge(
|
||||||
|
host: replica_host,
|
||||||
|
port: replica_port
|
||||||
|
)).raises(PG::ConnectionBad).once
|
||||||
|
|
||||||
2.times do
|
2.times do
|
||||||
expect { ActiveRecord::Base.postgresql_fallback_connection(config) }
|
expect { ActiveRecord::Base.postgresql_fallback_connection(config) }
|
||||||
|
|
Loading…
Reference in New Issue