diff --git a/Gemfile b/Gemfile index 949b45404ca..a80f23dbc0f 100644 --- a/Gemfile +++ b/Gemfile @@ -248,3 +248,5 @@ end gem 'webpush', require: false gem 'colored2', require: false gem 'maxminddb' + +gem 'rails_failover', require: false diff --git a/Gemfile.lock b/Gemfile.lock index f2c187b9b81..29f2fee8997 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -277,6 +277,8 @@ GEM nokogiri (>= 1.6) rails-html-sanitizer (1.3.0) loofah (~> 2.3) + rails_failover (0.1.0) + redis (~> 4) rails_multisite (2.1.2) activerecord (> 5.0, < 7) railties (> 5.0, < 7) @@ -509,6 +511,7 @@ DEPENDENCIES rack (= 2.2.2) rack-mini-profiler rack-protection + rails_failover rails_multisite railties (= 6.0.3) rake diff --git a/app/models/global_setting.rb b/app/models/global_setting.rb index f4425919ed3..21e5a137dcf 100644 --- a/app/models/global_setting.rb +++ b/app/models/global_setting.rb @@ -164,9 +164,15 @@ class GlobalSetting c[:port] = redis_port if redis_port if redis_slave_host && redis_slave_port - c[:slave_host] = redis_slave_host - c[:slave_port] = redis_slave_port - c[:connector] = DiscourseRedis::Connector + if ENV["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 end c[:password] = redis_password if redis_password.present? @@ -188,9 +194,15 @@ class GlobalSetting c[:port] = message_bus_redis_port if message_bus_redis_port if message_bus_redis_slave_host && message_bus_redis_slave_port - c[:slave_host] = message_bus_redis_slave_host - c[:slave_port] = message_bus_redis_slave_port - c[:connector] = DiscourseRedis::Connector + if ENV["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 end c[:password] = message_bus_redis_password if message_bus_redis_password.present? diff --git a/config/initializers/001-redis.rb b/config/initializers/001-redis.rb index d11303a9d59..14ce997b8f9 100644 --- a/config/initializers/001-redis.rb +++ b/config/initializers/001-redis.rb @@ -4,3 +4,20 @@ if Rails.env.development? && ENV['DISCOURSE_FLUSH_REDIS'] puts "Flushing redis (development mode)" Discourse.redis.flushdb end + +if ENV['RAILS_FAILOVER'] + require 'rails_failover' + + message_bus_keepalive_interval = MessageBus.keepalive_interval + + RailsFailover::Redis.register_master_up_callback do + MessageBus.keepalive_interval = message_bus_keepalive_interval + Discourse.clear_readonly! + Discourse.request_refresh! + end + + RailsFailover::Redis.register_master_down_callback do + # Disables MessageBus keepalive when Redis is in readonly mode + MessageBus.keepalive_interval = 0 + end +end