Skip to content

Commit

Permalink
Refactored SentinelBackedReplication and ServerSentinel to match disc…
Browse files Browse the repository at this point in the history
…ussions in predis#131
  • Loading branch information
Ville Mattila committed Aug 12, 2013
1 parent 1d1064b commit d079fa5
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* @link http://redis.io/topics/sentinel
* @author Ville Mattila <ville@eventio.fi>
*/
class Sentinel extends AbstractCommand
class ServerSentinel extends AbstractCommand
{
/**
* {@inheritdoc}
Expand All @@ -25,9 +25,6 @@ public function getId()
return 'SENTINEL';
}

// FIXME: Unnecessary getHash()
public function getHash() { return 'temp-hash'; }

/**
* {@inheritdoc}
*/
Expand Down
124 changes: 93 additions & 31 deletions lib/Predis/Connection/SentinelBackedReplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Predis\Connection;

use Predis\Command\CommandInterface;
use Predis\Command\ServerSentinel;
use Predis\Replication\ReplicationStrategy;

/**
Expand All @@ -20,29 +21,39 @@
class SentinelBackedReplication extends MasterSlaveReplication
{
/**
* Predis Client used to connect the sentinels.
*
* @var \Predis\Client
* Sentinel connections definition
*/
protected $sentinelClient;
protected $sentinelConnections;

/**
* Name of the master (in sentinel configuration)
*/
protected $sentinelMasterName;

/**
* @param array|string|ConnectionInterface $sentinelConnection Sentinel connection definition, anything that \Predis\Client accepts as constructor first argument
* @param string $masterName Sentinel master name
* @param ReplicationStrategy $strategy ReplicationStrategy passed to MasterSlaveReplication
* The current sentinel connection instance
*
* @var SingleConnectionInterface
*/
protected $currentSentinelConnection;

/**
* @var ConnectionFactory
*/
protected $connectionFactory;

/**
* @param array $sentinelConnections Sentinel connections definition
* @param string $masterName Sentinel master name
* @param ReplicationStrategy $strategy ReplicationStrategy passed to MasterSlaveReplication
*/
public function __construct($sentinelConnection, $masterName, ReplicationStrategy $strategy = null)
public function __construct(array $sentinelConnections, $masterName, ReplicationStrategy $strategy = null)
{
parent::__construct($strategy);

// Creating connection to Sentinel
$this->sentinelClient = new \Predis\Client($sentinelConnection);
$this->sentinelConnections = $sentinelConnections;
$this->sentinelMasterName = $masterName;
$this->connectionFactory = new ConnectionFactory();
}

/**
Expand All @@ -58,29 +69,80 @@ protected function check()
}

/**
* This function makes a query to the configured Sentionels and receive the master & slave configuration
* Returns the current sentinel connection or builds a new, if none
* is currently active.
*
* @return SingleConnectionInterface
*/
protected function querySentinels()
private function getSentinelConnection()
{
// Querying sentinels for master configuration
$masterResult = $this->sentinelClient->sentinel('get-master-addr-by-name', $this->sentinelMasterName);
$masterConnection = new StreamConnection(new ConnectionParameters(array(
'host' => $masterResult[0],
'port' => $masterResult[1],
'alias' => 'master'
)));

$this->add($masterConnection);

// Slave configuration
$slavesResult = $this->sentinelClient->sentinel('slaves',$this->sentinelMasterName);
foreach ($slavesResult as $slave) {
$slaveConnection = new StreamConnection(new ConnectionParameters(array(
'host' => $slave[3],
'port' => $slave[5]
)));

$this->add($slaveConnection);
if (null === $this->currentSentinelConnection) {
// In case there is no more sentinel connections, we'll throw
// an exception
if (count($this->sentinelConnections) < 1) {
throw new \Predis\ClientException('No working sentinels.');
}

// Otherwise, shifting one connection definition from the stack
$connectionDef = array_shift($this->sentinelConnections);
$this->currentSentinelConnection = $this->connectionFactory->create($connectionDef);
}

return $this->currentSentinelConnection;
}

/**
* Discards the current sentinel connection
*/
private function discardCurrentSentinel()
{
trigger_error('Sentinel connection ' . $this->currentSentinelConnection . ' failed, discarding.');
$this->currentSentinelConnection = null;
}

/**
* Creates a new ServerSentinel instance with given arguments.
*/
private function createSentinelCommand($arguments = array()) {
$command = new ServerSentinel();
$command->setArguments($arguments);
return $command;
}

/**
* This function makes a query to the configured sentinels. The query loops through
*/
protected function querySentinels()
{
do {
$sentinel = $this->getSentinelConnection();

try {
// Querying sentinels for master configuration
$masterResult = $sentinel->executeCommand($this->createSentinelCommand(array('get-master-addr-by-name', $this->sentinelMasterName)));
$masterConnection = $this->connectionFactory->create(new ConnectionParameters(array(
'host' => $masterResult[0],
'port' => $masterResult[1],
'alias' => 'master'
)));

$this->add($masterConnection);

// Slave configuration
$slavesResult = $sentinel->executeCommand($this->createSentinelCommand(array('slaves', $this->sentinelMasterName)));
foreach ($slavesResult as $slave) {
$slaveConnection = $this->connectionFactory->create(new ConnectionParameters(array(
'host' => $slave[3],
'port' => $slave[5]
)));

$this->add($slaveConnection);
}

break;
} catch (\Predis\Connection\ConnectionException $exception) {
$this->discardCurrentSentinel();
}
} while(true);
}
}
2 changes: 1 addition & 1 deletion lib/Predis/Profile/ServerVersion26.php
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ public function getSupportedCommands()
'info' => 'Predis\Command\ServerInfoV26x',
'time' => 'Predis\Command\ServerTime',

'sentinel' => 'Predis\Command\Sentinel',
'sentinel' => 'Predis\Command\ServerSentinel',
);
}
}
5 changes: 4 additions & 1 deletion sentinel_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

\Predis\Autoloader::register();

$sentinel = new \Predis\Connection\SentinelBackedReplication(array('tcp://127.0.0.1:6380'),'mymaster');
$sentinelConnections = array('tcp://127.0.0.1:26379', 'tcp://127.0.0.1:26380');
shuffle($sentinelConnections);

$sentinel = new \Predis\Connection\SentinelBackedReplication($sentinelConnections,'mymaster');
$client = new \Predis\Client($sentinel);

echo $client->get('test'); // From slave
Expand Down

0 comments on commit d079fa5

Please sign in to comment.