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().
This commit is contained in:
Daniele Alessandri
2015-08-16 16:20:16 +02:00
parent 587fbbc446
commit 8d15503d6c
@@ -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);
}
}