mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Allow Postgres to trigger readonly mode for the site.
This commit is contained in:
parent
c10a8d481d
commit
16408cee06
@ -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
|
render_json_error I18n.t("rate_limiter.too_many_requests", time_left: time_left), type: :rate_limit, status: 429
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rescue_from PG::ReadOnlySqlTransaction do |e|
|
||||||
|
Discourse.received_readonly!
|
||||||
|
raise Discourse::ReadOnly
|
||||||
|
end
|
||||||
|
|
||||||
rescue_from Discourse::NotLoggedIn do |e|
|
rescue_from Discourse::NotLoggedIn do |e|
|
||||||
raise e if Rails.env.test?
|
raise e if Rails.env.test?
|
||||||
|
|
||||||
|
@ -93,6 +93,19 @@ module Discourse
|
|||||||
end
|
end
|
||||||
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
|
def self.disabled_plugin_names
|
||||||
plugins.select {|p| !p.enabled?}.map(&:name)
|
plugins.select {|p| !p.enabled?}.map(&:name)
|
||||||
end
|
end
|
||||||
@ -202,7 +215,7 @@ module Discourse
|
|||||||
end
|
end
|
||||||
|
|
||||||
def self.readonly_mode?
|
def self.readonly_mode?
|
||||||
DiscourseRedis.recently_readonly? || !!$redis.get(readonly_mode_key)
|
recently_readonly? || !!$redis.get(readonly_mode_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.request_refresh!
|
def self.request_refresh!
|
||||||
|
@ -4,19 +4,6 @@
|
|||||||
require_dependency 'cache'
|
require_dependency 'cache'
|
||||||
class DiscourseRedis
|
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)
|
def self.raw_connection(config = nil)
|
||||||
config ||= self.config
|
config ||= self.config
|
||||||
redis_opts = {host: config['host'], port: config['port'], db: config['db']}
|
redis_opts = {host: config['host'], port: config['port'], db: config['db']}
|
||||||
@ -51,10 +38,10 @@ class DiscourseRedis
|
|||||||
yield
|
yield
|
||||||
rescue Redis::CommandError => ex
|
rescue Redis::CommandError => ex
|
||||||
if ex.message =~ /READONLY/
|
if ex.message =~ /READONLY/
|
||||||
unless DiscourseRedis.recently_readonly?
|
unless Discourse.recently_readonly?
|
||||||
STDERR.puts "WARN: Redis is in a readonly state. Performed a noop"
|
STDERR.puts "WARN: Redis is in a readonly state. Performed a noop"
|
||||||
end
|
end
|
||||||
DiscourseRedis.received_readonly!
|
Discourse.received_readonly!
|
||||||
else
|
else
|
||||||
raise ex
|
raise ex
|
||||||
end
|
end
|
||||||
|
@ -106,11 +106,6 @@ describe Discourse do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context "#readonly_mode?" do
|
context "#readonly_mode?" do
|
||||||
|
|
||||||
after do
|
|
||||||
DiscourseRedis.clear_readonly!
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is false by default" do
|
it "is false by default" do
|
||||||
expect(Discourse.readonly_mode?).to eq(false)
|
expect(Discourse.readonly_mode?).to eq(false)
|
||||||
end
|
end
|
||||||
@ -120,8 +115,8 @@ describe Discourse do
|
|||||||
expect(Discourse.readonly_mode?).to eq(true)
|
expect(Discourse.readonly_mode?).to eq(true)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "returns true when DiscourseRedis is recently read only" do
|
it "returns true when Discourse is recently read only" do
|
||||||
DiscourseRedis.received_readonly!
|
Discourse.received_readonly!
|
||||||
expect(Discourse.readonly_mode?).to eq(true)
|
expect(Discourse.readonly_mode?).to eq(true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -114,7 +114,7 @@ describe TopicsController do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "returns a readonly header if the site is read only" do
|
it "returns a readonly header if the site is read only" do
|
||||||
DiscourseRedis.received_readonly!
|
Discourse.received_readonly!
|
||||||
get :show, {topic_id: topic.id}
|
get :show, {topic_id: topic.id}
|
||||||
expect(response.headers['Discourse-Readonly']).to eq('true')
|
expect(response.headers['Discourse-Readonly']).to eq('true')
|
||||||
end
|
end
|
||||||
|
@ -112,7 +112,7 @@ Spork.prefork do
|
|||||||
# very expensive IO operations
|
# very expensive IO operations
|
||||||
SiteSetting.automatically_download_gravatars = false
|
SiteSetting.automatically_download_gravatars = false
|
||||||
|
|
||||||
DiscourseRedis.clear_readonly!
|
Discourse.clear_readonly!
|
||||||
|
|
||||||
I18n.locale = :en
|
I18n.locale = :en
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user