Skip to content

Commit

Permalink
DEV: Use rails_failover gem for ActiveRecord and Redis failover handling
Browse files Browse the repository at this point in the history
  • Loading branch information
tgxworld committed Jun 15, 2020
1 parent 6780d4d commit 58e52c0
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 461 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -250,4 +250,4 @@ gem 'webpush', require: false
gem 'colored2', require: false
gem 'maxminddb'

gem 'rails_failover', require: false, git: 'https://github.com/discourse/rails_failover'
gem 'rails_failover', require: false
13 changes: 4 additions & 9 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
GIT
remote: https://github.com/discourse/rails_failover
revision: 66602aa73785851b81c506f0023d3c2a2e40de0a
specs:
rails_failover (0.4.0)
activerecord (~> 6.0)
railties (~> 6.0)

GEM
remote: https://rubygems.org/
specs:
Expand Down Expand Up @@ -288,6 +280,9 @@ GEM
nokogiri (>= 1.6)
rails-html-sanitizer (1.3.0)
loofah (~> 2.3)
rails_failover (0.5.0)
activerecord (~> 6.0)
railties (~> 6.0)
rails_multisite (2.3.0)
activerecord (> 5.0, < 7)
railties (> 5.0, < 7)
Expand Down Expand Up @@ -526,7 +521,7 @@ DEPENDENCIES
rack (= 2.2.2)
rack-mini-profiler
rack-protection
rails_failover!
rails_failover
rails_multisite
railties (= 6.0.3.1)
rake
Expand Down
30 changes: 6 additions & 24 deletions app/models/global_setting.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,6 @@ def self.database_config
end
end

if hash["replica_host"]
if !ENV["ACTIVE_RECORD_RAILS_FAILOVER"]
hash["adapter"] = "postgresql_fallback"
end
end

hostnames = [ hostname ]
hostnames << backup_hostname if backup_hostname.present?

Expand Down Expand Up @@ -170,15 +164,9 @@ def self.redis_config
c[:port] = redis_port if redis_port

if redis_slave_host && redis_slave_port
if ENV["REDIS_RAILS_FAILOVER"]
c[:replica_host] = redis_slave_host
c[:replica_port] = redis_slave_port
c[:connector] = RailsFailover::Redis::Connector
else
c[:slave_host] = redis_slave_host
c[:slave_port] = redis_slave_port
c[:connector] = DiscourseRedis::Connector
end
c[:replica_host] = redis_slave_host
c[:replica_port] = redis_slave_port
c[:connector] = RailsFailover::Redis::Connector
end

c[:password] = redis_password if redis_password.present?
Expand All @@ -200,15 +188,9 @@ def self.message_bus_redis_config
c[:port] = message_bus_redis_port if message_bus_redis_port

if message_bus_redis_slave_host && message_bus_redis_slave_port
if ENV["REDIS_RAILS_FAILOVER"]
c[:replica_host] = message_bus_redis_slave_host
c[:replica_port] = message_bus_redis_slave_port
c[:connector] = RailsFailover::Redis::Connector
else
c[:slave_host] = message_bus_redis_slave_host
c[:slave_port] = message_bus_redis_slave_port
c[:connector] = DiscourseRedis::Connector
end
c[:replica_host] = message_bus_redis_slave_host
c[:replica_port] = message_bus_redis_slave_port
c[:connector] = RailsFailover::Redis::Connector
end

c[:password] = message_bus_redis_password if message_bus_redis_password.present?
Expand Down
10 changes: 2 additions & 8 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
require 'action_view/railtie'
require 'action_mailer/railtie'
require 'sprockets/railtie'
require 'rails_failover/active_record'
require 'rails_failover/redis'

# Plugin related stuff
require_relative '../lib/plugin_initialization_guard'
Expand All @@ -27,14 +29,6 @@

require_relative '../lib/plugin_gem'

if ENV['ACTIVE_RECORD_RAILS_FAILOVER']
require 'rails_failover/active_record'
end

if ENV['REDIS_RAILS_FAILOVER']
require 'rails_failover/redis'
end

# Global config
require_relative '../app/models/global_setting'
GlobalSetting.configure!
Expand Down
102 changes: 36 additions & 66 deletions config/initializers/002-rails_failover.rb
Original file line number Diff line number Diff line change
@@ -1,81 +1,51 @@
# frozen_string_literal: true

if ENV["REDIS_RAILS_FAILOVER"]
message_bus_keepalive_interval = nil
message_bus_keepalive_interval = nil

RailsFailover::Redis.on_failover do
message_bus_keepalive_interval = MessageBus.keepalive_interval
MessageBus.keepalive_interval = -1 # Disable MessageBus keepalive_interval
Discourse.received_redis_readonly!
end
RailsFailover::Redis.on_failover do
message_bus_keepalive_interval = MessageBus.keepalive_interval
MessageBus.keepalive_interval = -1 # Disable MessageBus keepalive_interval
Discourse.received_redis_readonly!
end

RailsFailover::Redis.on_fallback do
Discourse.clear_redis_readonly!
Discourse.request_refresh!
MessageBus.keepalive_interval = message_bus_keepalive_interval
end
RailsFailover::Redis.on_fallback do
Discourse.clear_redis_readonly!
Discourse.request_refresh!
MessageBus.keepalive_interval = message_bus_keepalive_interval
end

if ENV["ACTIVE_RECORD_RAILS_FAILOVER"]
if Rails.configuration.multisite
if ActiveRecord::Base.current_role == ActiveRecord::Base.reading_role
RailsMultisite::ConnectionManagement.default_connection_handler =
ActiveRecord::Base.connection_handlers[ActiveRecord::Base.reading_role]
end
if Rails.configuration.multisite
if ActiveRecord::Base.current_role == ActiveRecord::Base.reading_role
RailsMultisite::ConnectionManagement.default_connection_handler =
ActiveRecord::Base.connection_handlers[ActiveRecord::Base.reading_role]
end
end

RailsFailover::ActiveRecord.on_failover do
RailsMultisite::ConnectionManagement.each_connection do
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
Sidekiq.pause!("pg_failover") if !Sidekiq.paused?
end
rescue => e
Rails.logger.warn "#{e.class} #{e.message}: #{e.backtrace.join("\n")}"
false
RailsFailover::ActiveRecord.on_failover do
RailsMultisite::ConnectionManagement.each_connection do
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
Sidekiq.pause!("pg_failover") if !Sidekiq.paused?
end
end

RailsFailover::ActiveRecord.on_fallback do
RailsMultisite::ConnectionManagement.each_connection do
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
Sidekiq.unpause! if Sidekiq.paused?
end

if Rails.configuration.multisite
RailsMultisite::ConnectionManagement.default_connection_handler =
ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
end
rescue => e
Rails.logger.warn "#{e.class} #{e.message}: #{e.backtrace.join("\n")}"
false
RailsFailover::ActiveRecord.on_fallback do
RailsMultisite::ConnectionManagement.each_connection do
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
Sidekiq.unpause! if Sidekiq.paused?
end

module Discourse
PG_FORCE_READONLY_MODE_KEY ||= 'readonly_mode:postgres_force'

READONLY_KEYS.push(PG_FORCE_READONLY_MODE_KEY)

def self.enable_pg_force_readonly_mode
Discourse.redis.set(PG_FORCE_READONLY_MODE_KEY, 1)
Sidekiq.pause!("pg_failover") if !Sidekiq.paused?
MessageBus.publish(readonly_channel, true)
true
end

def self.disable_pg_force_readonly_mode
result = Discourse.redis.del(PG_FORCE_READONLY_MODE_KEY)
Sidekiq.unpause!
MessageBus.publish(readonly_channel, false)
result > 0
end
if Rails.configuration.multisite
RailsMultisite::ConnectionManagement.default_connection_handler =
ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
end
end

RailsFailover::ActiveRecord.register_force_reading_role_callback do
Discourse.redis.exists?(
Discourse::PG_READONLY_MODE_KEY,
Discourse::PG_FORCE_READONLY_MODE_KEY
)
rescue => e
Rails.logger.warn "#{e.class} #{e.message}: #{e.backtrace.join("\n")}"
false
end
RailsFailover::ActiveRecord.register_force_reading_role_callback do
Discourse.redis.exists?(
Discourse::PG_READONLY_MODE_KEY,
Discourse::PG_FORCE_READONLY_MODE_KEY
)
rescue => e
Rails.logger.warn "#{e.class} #{e.message}: #{e.backtrace.join("\n")}"
false
end
11 changes: 3 additions & 8 deletions config/initializers/200-first_middlewares.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,7 @@
# Multisite needs to be first, because the request tracker and message bus rely on it
Rails.configuration.middleware.unshift RailsMultisite::Middleware, RailsMultisite::DiscoursePatches.config
Rails.configuration.middleware.delete ActionDispatch::Executor
end

if ENV["ACTIVE_RECORD_RAILS_FAILOVER"]
if Rails.configuration.multisite
Rails.configuration.middleware.insert_after(RailsMultisite::Middleware, RailsFailover::ActiveRecord::Middleware)
else
Rails.configuration.middleware.insert_before(MessageBus::Rack::Middleware, RailsFailover::ActiveRecord::Middleware)
end
Rails.configuration.middleware.insert_after(RailsMultisite::Middleware, RailsFailover::ActiveRecord::Middleware)
else
Rails.configuration.middleware.insert_before(MessageBus::Rack::Middleware, RailsFailover::ActiveRecord::Middleware)
end
Loading

0 comments on commit 58e52c0

Please sign in to comment.