diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index bfe6462ff..1c9bdbbd8 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -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?
 
diff --git a/lib/discourse.rb b/lib/discourse.rb
index b4527dfd0..44d708e2a 100644
--- a/lib/discourse.rb
+++ b/lib/discourse.rb
@@ -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!
diff --git a/lib/discourse_redis.rb b/lib/discourse_redis.rb
index b0a56d29b..7c33dbbd1 100644
--- a/lib/discourse_redis.rb
+++ b/lib/discourse_redis.rb
@@ -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
diff --git a/spec/components/discourse_spec.rb b/spec/components/discourse_spec.rb
index 09426698a..45685d92e 100644
--- a/spec/components/discourse_spec.rb
+++ b/spec/components/discourse_spec.rb
@@ -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
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index eb35d6caa..9d0e17c0a 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -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
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 672981c92..63b3b45b0 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -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