Merge pull request #4297 from tgxworld/handle_user_enabled_readonly_mode

Handle user enabled readonly mode
This commit is contained in:
Guo Xiang Tan 2016-07-05 19:54:32 +08:00 committed by GitHub
commit f256e3afb6
3 changed files with 87 additions and 45 deletions

View File

@ -95,7 +95,7 @@ class Admin::BackupsController < Admin::AdminController
def readonly def readonly
enable = params.fetch(:enable).to_s == "true" enable = params.fetch(:enable).to_s == "true"
enable ? Discourse.enable_readonly_mode : Discourse.disable_readonly_mode enable ? Discourse.enable_readonly_mode(user_enabled: true) : Discourse.disable_readonly_mode(user_enabled: true)
render nothing: true render nothing: true
end end

View File

@ -197,10 +197,19 @@ module Discourse
base_url_no_prefix + base_uri base_url_no_prefix + base_uri
end end
def self.enable_readonly_mode READONLY_MODE_KEY_TTL ||= 60
$redis.set(readonly_mode_key, 1) READONLY_MODE_KEY ||= 'readonly_mode'.freeze
MessageBus.publish(readonly_channel, true) USER_READONLY_MODE_KEY ||= 'readonly_mode:user'.freeze
def self.enable_readonly_mode(user_enabled: false)
if user_enabled
$redis.set(USER_READONLY_MODE_KEY, 1)
else
$redis.setex(READONLY_MODE_KEY, READONLY_MODE_KEY_TTL, 1)
keep_readonly_mode keep_readonly_mode
end
MessageBus.publish(readonly_channel, true)
true true
end end
@ -208,20 +217,21 @@ module Discourse
# extend the expiry by 1 minute every 30 seconds # extend the expiry by 1 minute every 30 seconds
Thread.new do Thread.new do
while readonly_mode? while readonly_mode?
$redis.expire(readonly_mode_key, 1.minute) $redis.expire(READONLY_MODE_KEY, READONLY_MODE_KEY_TTL)
sleep 30.seconds sleep 30.seconds
end end
end end
end end
def self.disable_readonly_mode def self.disable_readonly_mode(user_enabled: false)
$redis.del(readonly_mode_key) key = user_enabled ? USER_READONLY_MODE_KEY : READONLY_MODE_KEY
$redis.del(key)
MessageBus.publish(readonly_channel, false) MessageBus.publish(readonly_channel, false)
true true
end end
def self.readonly_mode? def self.readonly_mode?
recently_readonly? || !!$redis.get(readonly_mode_key) recently_readonly? || !!$redis.get(READONLY_MODE_KEY)
end end
def self.request_refresh! def self.request_refresh!
@ -290,10 +300,6 @@ module Discourse
Rails.configuration.action_controller.asset_host Rails.configuration.action_controller.asset_host
end end
def self.readonly_mode_key
"readonly_mode"
end
def self.readonly_channel def self.readonly_channel
"/site/read-only" "/site/read-only"
end end

View File

@ -85,38 +85,73 @@ describe Discourse do
end end
context "#enable_readonly_mode" do context 'readonly mode' do
let(:readonly_mode_key) { Discourse::READONLY_MODE_KEY }
let(:readonly_mode_ttl) { Discourse::READONLY_MODE_KEY_TTL }
let(:user_readonly_mode_key) { Discourse::USER_READONLY_MODE_KEY }
after do
$redis.del(readonly_mode_key)
$redis.del(user_readonly_mode_key)
end
def assert_readonly_mode(message, key, ttl = -1)
expect(message.channel).to eq(Discourse.readonly_channel)
expect(message.data).to eq(true)
expect($redis.get(key)).to eq("1")
expect($redis.ttl(key)).to eq(ttl)
end
def assert_readonly_mode_disabled(message, key)
expect(message.channel).to eq(Discourse.readonly_channel)
expect(message.data).to eq(false)
expect($redis.get(key)).to eq(nil)
end
describe ".enable_readonly_mode" do
it "adds a key in redis and publish a message through the message bus" do it "adds a key in redis and publish a message through the message bus" do
$redis.expects(:set).with(Discourse.readonly_mode_key, 1) expect($redis.get(readonly_mode_key)).to eq(nil)
MessageBus.expects(:publish).with(Discourse.readonly_channel, true) message = MessageBus.track_publish { Discourse.enable_readonly_mode }.first
Discourse.enable_readonly_mode assert_readonly_mode(message, readonly_mode_key, readonly_mode_ttl)
end end
context 'user enabled readonly mode' do
it "adds a key in redis and publish a message through the message bus" do
expect($redis.get(user_readonly_mode_key)).to eq(nil)
message = MessageBus.track_publish { Discourse.enable_readonly_mode(user_enabled: true) }.first
assert_readonly_mode(message, user_readonly_mode_key)
end
end
end end
context "#disable_readonly_mode" do describe ".disable_readonly_mode" do
it "removes a key from redis and publish a message through the message bus" do it "removes a key from redis and publish a message through the message bus" do
$redis.expects(:del).with(Discourse.readonly_mode_key) Discourse.enable_readonly_mode
MessageBus.expects(:publish).with(Discourse.readonly_channel, false)
message = MessageBus.track_publish do
Discourse.disable_readonly_mode Discourse.disable_readonly_mode
end.first
assert_readonly_mode_disabled(message, readonly_mode_key)
end end
context 'user disabled readonly mode' do
it "removes readonly key in redis and publish a message through the message bus" do
Discourse.enable_readonly_mode(user_enabled: true)
message = MessageBus.track_publish { Discourse.disable_readonly_mode(user_enabled: true) }.first
assert_readonly_mode_disabled(message, user_readonly_mode_key)
end
end
end end
context "#readonly_mode?" do describe ".readonly_mode?" do
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
it "returns true when the key is present in redis" do it "returns true when the key is present in redis" do
begin $redis.set(readonly_mode_key, 1)
$redis.set(Discourse.readonly_mode_key, 1)
expect(Discourse.readonly_mode?).to eq(true) expect(Discourse.readonly_mode?).to eq(true)
ensure
$redis.del(Discourse.readonly_mode_key)
end
end end
it "returns true when Discourse is recently read only" do it "returns true when Discourse is recently read only" do
@ -125,12 +160,13 @@ describe Discourse do
end end
end end
context ".received_readonly!" do describe ".received_readonly!" do
it "sets the right time" do it "sets the right time" do
time = Discourse.received_readonly! time = Discourse.received_readonly!
expect(Discourse.last_read_only['default']).to eq(time) expect(Discourse.last_read_only['default']).to eq(time)
end end
end end
end
context "#handle_exception" do context "#handle_exception" do