소스 검색

Implement transparent auto-retry of commands upon server failure.

By default, when the current server dies while executing a command Predis asks
for a new configuration to one of the sentinels and re-issues the same command.

This behavior can be disabled calling SentinelReplication::setAutomaticRetry().
Daniele Alessandri 9 년 전
부모
커밋
8d15503d6c
1개의 변경된 파일69개의 추가작업 그리고 0개의 파일을 삭제
  1. 69 0
      src/Connection/Aggregate/SentinelReplication.php

+ 69 - 0
src/Connection/Aggregate/SentinelReplication.php

@@ -11,6 +11,7 @@
 
 namespace Predis\Connection\Aggregate;
 
+use Predis\Command\CommandInterface;
 use Predis\Command\RawCommand;
 use Predis\Connection\ConnectionException;
 use Predis\Connection\Factory as ConnectionFactory;
@@ -54,6 +55,11 @@ class SentinelReplication extends MasterSlaveReplication
      */
     protected $sentinelTimeout = 0.100;
 
+    /**
+     * Flag for automatic retries of commands upon server failure.
+     */
+    protected $autoRetry = true;
+
     /**
      * @param array                      $sentinels         Sentinel servers connection parameters.
      * @param string                     $service           Name of the service for autodiscovery.
@@ -86,6 +92,16 @@ class SentinelReplication extends MasterSlaveReplication
         $this->sentinelTimeout = (float) $timeout;
     }
 
+    /**
+     * Set automatic retries of commands upon server failure.
+     *
+     * @param bool $retry Retry value.
+     */
+    public function setAutomaticRetry($retry)
+    {
+        $this->autoRetry = (bool) $retry;
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -245,4 +261,57 @@ class SentinelReplication extends MasterSlaveReplication
             }
         }
     }
+
+    /**
+     * Retries the execution of a command upon server failure after asking a new
+     * configuration to one of the sentinels.
+     *
+     * @param string           $method  Actual method.
+     * @param CommandInterface $command Command instance.
+     *
+     * @return mixed
+     */
+    private function retryCommandOnFailure($method, $command)
+    {
+        SENTINEL_RETRY: {
+            try {
+                $response = parent::$method($command);
+            } catch (ConnectionException $exception) {
+                if (!$this->autoRetry) {
+                    throw $exception;
+                }
+
+                $exception->getConnection()->disconnect();
+                $this->querySentinel();
+
+                goto SENTINEL_RETRY;
+            }
+        }
+
+        return $response;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function writeRequest(CommandInterface $command)
+    {
+        $this->retryCommandOnFailure(__FUNCTION__, $command);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function readResponse(CommandInterface $command)
+    {
+        return $this->retryCommandOnFailure(__FUNCTION__, $command);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function executeCommand(CommandInterface $command)
+    {
+        return $this->retryCommandOnFailure(__FUNCTION__, $command);
+    }
 }