Improved fail-over in ReplicatedBagOStuff for redis
authorAaron Schulz <aschulz@wikimedia.org>
Fri, 1 May 2015 21:40:26 +0000 (14:40 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Sat, 2 May 2015 20:45:41 +0000 (13:45 -0700)
Bug: T96123
Change-Id: I3f37417a1a4f010b092a7718d43bfcdfe16e8f4c

includes/objectcache/RedisBagOStuff.php

index 9d5d0ef..2db4e9a 100644 (file)
@@ -374,10 +374,32 @@ class RedisBagOStuff extends BagOStuff {
 
                foreach ( $candidates as $tag ) {
                        $server = $this->serverTagMap[$tag];
+
                        $conn = $this->redisPool->getConnection( $server );
-                       if ( $conn ) {
-                               return array( $server, $conn );
+                       if ( !$conn ) {
+                               continue;
+                       }
+
+                       try {
+                               $info = $conn->info();
+                               // Check if this server has an unreachable redis master
+                               if ( $info['role'] === 'slave'
+                                       && $info['master_link_status'] === 'down'
+                                       && $this->automaticFailover
+                               ) {
+                                       // If the master cannot be reached, fail-over to the next server.
+                                       // If masters are in data-center A, and slaves in data-center B,
+                                       // this helps avoid the case were fail-over happens in A but not
+                                       // to the corresponding server in B (e.g. read/write mismatch).
+                                       continue;
+                               }
+                       } catch ( RedisException $e ) {
+                               // Server is not accepting commands
+                               $this->handleException( $conn, $e );
+                               continue;
                        }
+
+                       return array( $server, $conn );
                }
 
                $this->setLastError( BagOStuff::ERR_UNREACHABLE );