Browse Source

Implement ROLE for proper redis-sentinel support.

Once the client discovers the address of the master or a slave instance,
it must connect to that node and issue a ROLE command to verify that its
role still matches what the client got from the sentinel server.
Daniele Alessandri 9 years ago
parent
commit
f8b3f18abf
2 changed files with 49 additions and 1 deletions
  1. 25 1
      src/Connection/Aggregate/SentinelReplication.php
  2. 24 0
      src/Replication/RoleException.php

+ 25 - 1
src/Connection/Aggregate/SentinelReplication.php

@@ -11,6 +11,7 @@
 
 namespace Predis\Connection\Aggregate;
 
+use Predis\CommunicationException;
 use Predis\Command\CommandInterface;
 use Predis\Command\RawCommand;
 use Predis\Connection\ConnectionException;
@@ -19,6 +20,7 @@ use Predis\Connection\FactoryInterface as ConnectionFactoryInterface;
 use Predis\Connection\NodeConnectionInterface;
 use Predis\Connection\Parameters;
 use Predis\Replication\ReplicationStrategy;
+use Predis\Replication\RoleException;
 use Predis\Response\ErrorInterface as ErrorResponseInterface;
 use Predis\Response\ServerException;
 
@@ -324,6 +326,28 @@ class SentinelReplication extends MasterSlaveReplication
         }
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function getConnection(CommandInterface $command)
+    {
+        $connection = parent::getConnection($command);
+
+        if (!$connection->isConnected()) {
+            $role = $connection->executeCommand(RawCommand::create('ROLE'));
+
+            if ($connection === $this->master && $role[0] !== 'master') {
+                throw new RoleException($connection, "Expected master but got $role[0] [$connection]");
+            }
+
+            if ($connection !== $this->master && $role[0] !== 'slave') {
+                throw new RoleException($connection, "Expected slave but got $role[0] [$connection]");
+            }
+        }
+
+        return $connection;
+    }
+
     /**
      * Retries the execution of a command upon server failure after asking a new
      * configuration to one of the sentinels.
@@ -340,7 +364,7 @@ class SentinelReplication extends MasterSlaveReplication
         SENTINEL_RETRY: {
             try {
                 $response = parent::$method($command);
-            } catch (ConnectionException $exception) {
+            } catch (CommunicationException $exception) {
                 if ($retries == $this->retryLimit) {
                     throw $exception;
                 }

+ 24 - 0
src/Replication/RoleException.php

@@ -0,0 +1,24 @@
+<?php
+
+/*
+ * This file is part of the Predis package.
+ *
+ * (c) Daniele Alessandri <suppakilla@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Predis\Replication;
+
+use Predis\CommunicationException;
+
+/**
+ * Exception class that identifies a role mismatch when connecting to node
+ * managed by redis-sentinel.
+ *
+ * @author Daniele Alessandri <suppakilla@gmail.com>
+ */
+class RoleException extends CommunicationException
+{
+}