From 5d7f2971102b61ff557e4e847e2b3d2b7653e228 Mon Sep 17 00:00:00 2001 From: Daniele Alessandri Date: Sat, 30 Nov 2013 17:23:04 +0100 Subject: [PATCH] Send ASKING command when redis-cluster returns a -ASK response. We must always execute ASKING on the connection identified by the -ASK response before executing the actual command because not doing so will break the cluster specifications while redis-cluster is performing a resharding operation. --- lib/Predis/Connection/RedisCluster.php | 8 ++++++-- tests/Predis/Connection/RedisClusterTest.php | 21 ++++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/Predis/Connection/RedisCluster.php b/lib/Predis/Connection/RedisCluster.php index ff261af6..d3b11591 100644 --- a/lib/Predis/Connection/RedisCluster.php +++ b/lib/Predis/Connection/RedisCluster.php @@ -15,6 +15,7 @@ use Predis\ClientException; use Predis\NotSupportedException; use Predis\Cluster; use Predis\Command\CommandInterface; +use Predis\Command\RawCommand; use Predis\Response; /** @@ -279,10 +280,13 @@ class RedisCluster implements ClusterConnectionInterface, \IteratorAggregate, \C switch ($request) { case 'MOVED': $this->move($connection, $slot); - return $this->executeCommand($command); + $response = $this->executeCommand($command); + return $response; case 'ASK': - return $connection->executeCommand($command); + $connection->executeCommand(RawCommand::create('ASKING')); + $response = $connection->executeCommand($command); + return $response; default: throw new ClientException("Unexpected request type for a move request: $request"); diff --git a/tests/Predis/Connection/RedisClusterTest.php b/tests/Predis/Connection/RedisClusterTest.php index 60251e2c..bc60e3c7 100644 --- a/tests/Predis/Connection/RedisClusterTest.php +++ b/tests/Predis/Connection/RedisClusterTest.php @@ -434,7 +434,10 @@ class RedisClusterTest extends StandardTestCase ->will($this->onConsecutiveCalls($askResponse, 'foobar')); $connection2 = $this->getMockConnection('tcp://127.0.0.1:6380'); - $connection2->expects($this->exactly(1)) + $connection2->expects($this->at(2)) + ->method('executeCommand') + ->with($this->isRedisCommand('ASKING')); + $connection2->expects($this->at(3)) ->method('executeCommand') ->with($command) ->will($this->returnValue('foobar')); @@ -471,7 +474,10 @@ class RedisClusterTest extends StandardTestCase ->method('executeCommand'); $connection3 = $this->getMockConnection('tcp://127.0.0.1:6381'); - $connection3->expects($this->once()) + $connection3->expects($this->at(0)) + ->method('executeCommand') + ->with($this->isRedisCommand('ASKING')); + $connection3->expects($this->at(1)) ->method('executeCommand') ->with($command) ->will($this->returnValue('foobar')); @@ -605,6 +611,17 @@ class RedisClusterTest extends StandardTestCase // ---- HELPER METHODS ------------------------------------------------ // // ******************************************************************** // + /** + * Asserts that two arrays have the same values, even if with different order. + * + * @param string|CommandInterface $command Expected command or command ID. + * @param array $arguments Expected command arguments. + */ + protected function isRedisCommand($command = null, array $arguments = null) + { + return new \RedisCommandConstraint($command, $arguments); + } + /** * Returns a base mocked connection from Predis\Connection\SingleConnectionInterface. *