mirror of
https://github.com/predis/predis.git
synced 2026-08-30 04:02:22 +00:00
Retry all exceptions from Sentinel replicas (#1577)
* Retry SentinelReplication::retryCommandOnFailure on all classes with Throwable interface * Retry SentinelReplication::retryCommandOnFailure on all classes with Throwable interface * Fix coding style
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
|
||||
### Changed
|
||||
- Handle and retry `LOADING` errors from Sentinel replicas (#1536)
|
||||
- Retry all exceptions from Sentinel replicas (#1577)
|
||||
|
||||
### Fixed
|
||||
- Fixed PHP 8.4 deprecated call to `stream_context_set_option()` (#1545)
|
||||
|
||||
@@ -16,7 +16,6 @@ use InvalidArgumentException;
|
||||
use Predis\Command\Command;
|
||||
use Predis\Command\CommandInterface;
|
||||
use Predis\Command\RawCommand;
|
||||
use Predis\CommunicationException;
|
||||
use Predis\Connection\AbstractAggregateConnection;
|
||||
use Predis\Connection\ConnectionException;
|
||||
use Predis\Connection\FactoryInterface as ConnectionFactoryInterface;
|
||||
@@ -28,6 +27,7 @@ use Predis\Replication\RoleException;
|
||||
use Predis\Response\Error;
|
||||
use Predis\Response\ErrorInterface as ErrorResponseInterface;
|
||||
use Predis\Response\ServerException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
@@ -719,9 +719,12 @@ class SentinelReplication extends AbstractAggregateConnection implements Replica
|
||||
throw new ConnectionException($this->current, $response->getMessage());
|
||||
}
|
||||
break;
|
||||
} catch (CommunicationException $exception) {
|
||||
} catch (Throwable $exception) {
|
||||
$this->wipeServerList();
|
||||
$exception->getConnection()->disconnect();
|
||||
|
||||
if ($exception instanceof ConnectionException) {
|
||||
$exception->getConnection()->disconnect();
|
||||
}
|
||||
|
||||
if ($retries === $this->retryLimit) {
|
||||
throw $exception;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
namespace Predis\Connection\Replication;
|
||||
|
||||
use Exception;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Predis\Command;
|
||||
use Predis\Connection;
|
||||
@@ -1193,6 +1194,95 @@ class SentinelReplicationTest extends PredisTestCase
|
||||
$this->assertSame($cmdSetResponse, $replication->executeCommand($cmdSet));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testMethodExecuteCommandRetriesReadOnlyCommandOnNextSlaveOnConnectionException(): void
|
||||
{
|
||||
$sentinel1 = $this->getMockSentinelConnection('tcp://127.0.0.1:5381?role=sentinel');
|
||||
$sentinel1
|
||||
->expects($this->any())
|
||||
->method('executeCommand')
|
||||
->with($this->isRedisCommand(
|
||||
'SENTINEL', ['slaves', 'svc']
|
||||
))
|
||||
->willReturn(
|
||||
[
|
||||
[
|
||||
'name', '127.0.0.1:6383',
|
||||
'ip', '127.0.0.1',
|
||||
'port', '6383',
|
||||
'runid', '1c0bf1291797fbc5608c07a17da394147dc62817',
|
||||
'flags', 'slave',
|
||||
'master-host', '127.0.0.1',
|
||||
'master-port', '6381',
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
$master = $this->getMockConnection('tcp://127.0.0.1:6381?role=master');
|
||||
$master
|
||||
->expects($this->any())
|
||||
->method('isConnected')
|
||||
->willReturn(true);
|
||||
|
||||
$slave1 = $this->getMockConnection('tcp://127.0.0.1:6382?role=slave');
|
||||
$slave1
|
||||
->expects($this->any())
|
||||
->method('isConnected')
|
||||
->willReturn(true);
|
||||
|
||||
$slave1
|
||||
->expects($this->any())
|
||||
->method('disconnect');
|
||||
|
||||
$slave1
|
||||
->expects($this->once())
|
||||
->method('executeCommand')
|
||||
->with(
|
||||
$this->isRedisCommand('GET', ['key'])
|
||||
)
|
||||
->willThrowException(
|
||||
new Connection\ConnectionException($slave1, 'Unknown connection error [127.0.0.1:6382]')
|
||||
);
|
||||
|
||||
$slave2 = $this->getMockConnection('tcp://127.0.0.1:6383?role=slave');
|
||||
$slave2
|
||||
->expects($this->any())
|
||||
->method('isConnected')
|
||||
->willReturn(true);
|
||||
$slave2
|
||||
->expects($this->once())
|
||||
->method('executeCommand')
|
||||
->withConsecutive(
|
||||
[$this->isRedisCommand('GET', ['key'])]
|
||||
)
|
||||
->willReturnOnConsecutiveCalls(
|
||||
'value'
|
||||
);
|
||||
|
||||
/** @var Connection\FactoryInterface|MockObject */
|
||||
$factory = $this->getMockBuilder('Predis\Connection\FactoryInterface')->getMock();
|
||||
$factory
|
||||
->expects($this->once())
|
||||
->method('create')
|
||||
->with([
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '6383',
|
||||
'role' => 'slave',
|
||||
])
|
||||
->willReturn($slave2);
|
||||
|
||||
$replication = $this->getReplicationConnection('svc', [$sentinel1], $factory);
|
||||
|
||||
$replication->add($master);
|
||||
$replication->add($slave1);
|
||||
|
||||
self::assertSame('value', $replication->executeCommand(
|
||||
Command\RawCommand::create('get', 'key')
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -1237,7 +1327,7 @@ class SentinelReplicationTest extends PredisTestCase
|
||||
$this->isRedisCommand('GET', ['key'])
|
||||
)
|
||||
->willThrowException(
|
||||
new Connection\ConnectionException($slave1, 'Unknown connection error [127.0.0.1:6382]')
|
||||
new Exception('message')
|
||||
);
|
||||
|
||||
$slave2 = $this->getMockConnection('tcp://127.0.0.1:6383?role=slave');
|
||||
|
||||
Reference in New Issue
Block a user