Allow Postgres to trigger readonly mode for the site.

This commit is contained in:
Robin Ward 2015-04-29 11:49:58 -04:00
parent c10a8d481d
commit 16408cee06
6 changed files with 25 additions and 25 deletions

View File

@ -89,6 +89,11 @@ class ApplicationController < ActionController::Base
render_json_error I18n.t("rate_limiter.too_many_requests", time_left: time_left), type: :rate_limit, status: 429
end
rescue_from PG::ReadOnlySqlTransaction do |e|
Discourse.received_readonly!
raise Discourse::ReadOnly
end
rescue_from Discourse::NotLoggedIn do |e|
raise e if Rails.env.test?

View File

@ -93,6 +93,19 @@ module Discourse
end
end
def self.recently_readonly?
return false unless @last_read_only
@last_read_only > 15.seconds.ago
end
def self.received_readonly!
@last_read_only = Time.now
end
def self.clear_readonly!
@last_read_only = nil
end
def self.disabled_plugin_names
plugins.select {|p| !p.enabled?}.map(&:name)
end
@ -202,7 +215,7 @@ module Discourse
end
def self.readonly_mode?
DiscourseRedis.recently_readonly? || !!$redis.get(readonly_mode_key)
recently_readonly? || !!$redis.get(readonly_mode_key)
end
def self.request_refresh!

View File

@ -4,19 +4,6 @@
require_dependency 'cache'
class DiscourseRedis
def self.recently_readonly?
return false unless @last_read_only
@last_read_only > 15.seconds.ago
end
def self.received_readonly!
@last_read_only = Time.now
end
def self.clear_readonly!
@last_read_only = nil
end
def self.raw_connection(config = nil)
config ||= self.config
redis_opts = {host: config['host'], port: config['port'], db: config['db']}
@ -51,10 +38,10 @@ class DiscourseRedis
yield
rescue Redis::CommandError => ex
if ex.message =~ /READONLY/
unless DiscourseRedis.recently_readonly?
unless Discourse.recently_readonly?
STDERR.puts "WARN: Redis is in a readonly state. Performed a noop"
end
DiscourseRedis.received_readonly!
Discourse.received_readonly!
else
raise ex
end

View File

@ -106,11 +106,6 @@ describe Discourse do
end
context "#readonly_mode?" do
after do
DiscourseRedis.clear_readonly!
end
it "is false by default" do
expect(Discourse.readonly_mode?).to eq(false)
end
@ -120,8 +115,8 @@ describe Discourse do
expect(Discourse.readonly_mode?).to eq(true)
end
it "returns true when DiscourseRedis is recently read only" do
DiscourseRedis.received_readonly!
it "returns true when Discourse is recently read only" do
Discourse.received_readonly!
expect(Discourse.readonly_mode?).to eq(true)
end
end

View File

@ -114,7 +114,7 @@ describe TopicsController do
end
it "returns a readonly header if the site is read only" do
DiscourseRedis.received_readonly!
Discourse.received_readonly!
get :show, {topic_id: topic.id}
expect(response.headers['Discourse-Readonly']).to eq('true')
end

View File

@ -112,7 +112,7 @@ Spork.prefork do
# very expensive IO operations
SiteSetting.automatically_download_gravatars = false
DiscourseRedis.clear_readonly!
Discourse.clear_readonly!
I18n.locale = :en
end