Fixed Sentinel does not wipe servers on exception caused (#1694)

This commit is contained in:
Vladyslav Vildanov
2026-06-22 20:55:28 +03:00
committed by GitHub
parent b6b7f0d4e0
commit 09b8ce59dd
3 changed files with 77 additions and 2 deletions
+3
View File
@@ -4,6 +4,9 @@
### Added
- Make ZMSCORE command Prefixable and add to a ClusterStrategy (#1692)
### Fixed
- Fixed Sentinel does not wipe servers on exception caused (#1694)
## v3.5.1 (2026-06-11)
### Added
- Expose `pipeline()` API via `ClientInterface` (#1686)
@@ -33,6 +33,7 @@ use Predis\Response\ErrorInterface as ErrorResponseInterface;
use Predis\Response\ServerException;
use Predis\Retry\Retry;
use Predis\Retry\Strategy\ExponentialBackoff;
use Throwable;
/**
* @author Daniele Alessandri <suppakilla@gmail.com>
@@ -753,9 +754,12 @@ class SentinelReplication extends AbstractAggregateConnection implements Replica
return $response;
};
$failCallback = function (CommunicationException $exception) {
$failCallback = function (Throwable $exception) {
$this->wipeServerList();
$exception->getConnection()->disconnect();
if ($exception instanceof CommunicationException) {
$exception->getConnection()->disconnect();
}
};
return $retry->callWithRetry($doCallback, $failCallback);
@@ -17,6 +17,7 @@ use Predis\Command;
use Predis\Connection;
use Predis\Connection\Parameters;
use Predis\Connection\ParametersInterface;
use Predis\Connection\Resource\Exception\StreamInitException;
use Predis\Connection\Resource\StreamFactoryInterface;
use Predis\Connection\StreamConnection;
use Predis\Replication;
@@ -1496,6 +1497,73 @@ class SentinelReplicationTest extends PredisTestCase
));
}
/**
* @group disconnected
*/
public function testMethodExecuteCommandRetriesWriteCommandOnNewMasterOnStreamInitException(): void
{
$sentinel1 = $this->getMockSentinelConnection('tcp://127.0.0.1:5381?role=sentinel');
$sentinel1
->expects($this->any())
->method('executeCommand')
->with($this->isRedisCommand(
'SENTINEL', ['get-master-addr-by-name', 'svc']
))
->willReturn(
['127.0.0.1', '6391']
);
$masterOld = $this->getMockConnection('tcp://127.0.0.1:6381?role=master');
$masterOld
->expects($this->any())
->method('isConnected')
->willReturn(true);
$masterOld
->expects($this->once())
->method('executeCommand')
->with(
$this->isRedisCommand('DEL', ['key'])
)
->willThrowException(
new StreamInitException('Connection refused [tcp://127.0.0.1:6381]')
);
$masterNew = $this->getMockConnection('tcp://127.0.0.1:6391?role=master');
$masterNew
->expects($this->any())
->method('isConnected')
->willReturn(true);
$masterNew
->expects($this->once())
->method('executeCommand')
->withConsecutive(
[$this->isRedisCommand('DEL', ['key'])]
)
->willReturnOnConsecutiveCalls(
1
);
/** @var Connection\FactoryInterface|MockObject */
$factory = $this->getMockBuilder('Predis\Connection\FactoryInterface')->getMock();
$factory
->expects($this->once())
->method('create')
->with([
'host' => '127.0.0.1',
'port' => '6391',
'role' => 'master',
])
->willReturn($masterNew);
$replication = $this->getReplicationConnection('svc', [$sentinel1], $factory);
$replication->add($masterOld);
$this->assertSame(1, $replication->executeCommand(
Command\RawCommand::create('del', 'key')
));
}
/**
* @group disconnected
*/