FIX: Race-condition in fallback handlers (#8005)

FIX: Race-condition in fallback handlers (#8005)

Calling verify_master in multiple threads simultaneously would cause multiple threads to be spawned.

diff --git a/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb b/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb
index 7094eb5..ce37de7 100644
--- a/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb
+++ b/lib/active_record/connection_adapters/postgresql_fallback_adapter.rb
@@ -32,19 +32,21 @@ class PostgreSQLFallbackHandler
   end
 
   def verify_master
-    synchronize { return if @thread && @thread.alive? }
-
-    @thread = Thread.new do
-      while true do
-        thread = Thread.new { initiate_fallback_to_master }
-        thread.abort_on_exception = true
-        thread.join
-        break if synchronize { @masters_down.hash.empty? }
-        sleep 5
+    synchronize do
+      return if @thread && @thread.alive?
+
+      @thread = Thread.new do
+        while true do
+          thread = Thread.new { initiate_fallback_to_master }
+          thread.abort_on_exception = true
+          thread.join
+          break if synchronize { @masters_down.hash.empty? }
+          sleep 5
+        end
       end
-    end
 
-    @thread.abort_on_exception = true
+      @thread.abort_on_exception = true
+    end
   end
 
   def master_down?
diff --git a/lib/discourse_redis.rb b/lib/discourse_redis.rb
index d62113d..e63ec53 100644
--- a/lib/discourse_redis.rb
+++ b/lib/discourse_redis.rb
@@ -23,17 +23,19 @@ class DiscourseRedis
     end
 
     def verify_master
-      synchronize { return if @thread && @thread.alive? }
-
-      @thread = Thread.new do
-        loop do
-          begin
-            thread = Thread.new { initiate_fallback_to_master }
-            thread.join
-            break if synchronize { @master }
-            sleep 5
-          ensure
-            thread.kill
+      synchronize do
+        return if @thread && @thread.alive?
+
+        @thread = Thread.new do
+          loop do
+            begin
+              thread = Thread.new { initiate_fallback_to_master }
+              thread.join
+              break if synchronize { @master }
+              sleep 5
+            ensure
+              thread.kill
+            end
           end
         end
       end

GitHub sha: 6924f1ab

1 Like