Skip to content

Commit 6021daf

Browse files
mustafaakbelMustafa AKBELtillkruss
authored
Treat LOADING Errors as Connection Failures to Retry with Next Replica (#1536)
* fix(sentinel-replication): Treat LOADING error responses as ConnectionException to allow retry mechanism to discard the current replica and switch to the next available one. * fix(sentinel-replication): add changelog entries for LOADING response handling * Update CHANGELOG.md * Update CHANGELOG.md --------- Co-authored-by: Mustafa AKBEL <[email protected]> Co-authored-by: Till Krüss <[email protected]>
1 parent 2372b5c commit 6021daf

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
## Changelog
22

33
## Unreleased
4+
### Changed
5+
- Handle and retry `LOADING` errors from Sentinel replicas (#1536)
6+
47
### Fixed
58
- Fixed PHP 8.4 deprecated call to `stream_context_set_option()` (#1545)
69
- Fixed return type for `ZCOUNT` to be `int` (#1547)

src/Connection/Replication/SentinelReplication.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,9 @@ private function retryCommandOnFailure(CommandInterface $command, $method)
715715
while ($retries <= $this->retryLimit) {
716716
try {
717717
$response = $this->getConnectionByCommand($command)->$method($command);
718+
if ($response instanceof Error && $response->getErrorType() === 'LOADING') {
719+
throw new ConnectionException($this->current, $response->getMessage());
720+
}
718721
break;
719722
} catch (CommunicationException $exception) {
720723
$this->wipeServerList();

tests/Predis/Connection/Replication/SentinelReplicationTest.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1599,6 +1599,91 @@ public function connectionsProvider(): array
15991599
];
16001600
}
16011601

1602+
/**
1603+
* @group disconnected
1604+
*/
1605+
public function testDiscardsSlaveWhenRespondsLOADINGAndExecutesReadOnlyCommandOnNextSlave(): void
1606+
{
1607+
$sentinel1 = $this->getMockSentinelConnection('tcp://127.0.0.1:5381?role=sentinel');
1608+
$sentinel1
1609+
->expects($this->any())
1610+
->method('executeCommand')
1611+
->with($this->isRedisCommand(
1612+
'SENTINEL', ['slaves', 'svc']
1613+
))
1614+
->willReturn(
1615+
[
1616+
[
1617+
'name', '127.0.0.1:6383',
1618+
'ip', '127.0.0.1',
1619+
'port', '6383',
1620+
'runid', '1c0bf1291797fbc5608c07a17da394147dc62817',
1621+
'flags', 'slave',
1622+
'master-host', '127.0.0.1',
1623+
'master-port', '6381',
1624+
],
1625+
]
1626+
);
1627+
1628+
$master = $this->getMockConnection('tcp://127.0.0.1:6381?role=master');
1629+
$master
1630+
->expects($this->any())
1631+
->method('isConnected')
1632+
->willReturn(true);
1633+
1634+
$slave1 = $this->getMockConnection('tcp://127.0.0.1:6382?role=slave');
1635+
$slave1
1636+
->expects($this->any())
1637+
->method('isConnected')
1638+
->willReturn(true);
1639+
$slave1
1640+
->expects($this->once())
1641+
->method('executeCommand')
1642+
->with(
1643+
$this->isRedisCommand('GET', ['key'])
1644+
)
1645+
->willReturn(
1646+
new Response\Error('LOADING')
1647+
);
1648+
1649+
$slave2 = $this->getMockConnection('tcp://127.0.0.1:6383?role=slave');
1650+
$slave2
1651+
->expects($this->any())
1652+
->method('isConnected')
1653+
->willReturn(true);
1654+
$slave2
1655+
->expects($this->once())
1656+
->method('executeCommand')
1657+
->withConsecutive(
1658+
[$this->isRedisCommand('GET', ['key'])]
1659+
)
1660+
->willReturnOnConsecutiveCalls(
1661+
'value'
1662+
);
1663+
1664+
/** @var Connection\FactoryInterface|MockObject */
1665+
$factory = $this->getMockBuilder('Predis\Connection\FactoryInterface')->getMock();
1666+
$factory
1667+
->expects($this->once())
1668+
->method('create')
1669+
->with([
1670+
'host' => '127.0.0.1',
1671+
'port' => '6383',
1672+
'role' => 'slave',
1673+
])
1674+
->willReturn($slave2);
1675+
1676+
$replication = $this->getReplicationConnection('svc', [$sentinel1], $factory);
1677+
1678+
$replication->add($master);
1679+
$replication->add($slave1);
1680+
1681+
$this->assertSame('value', $replication->executeCommand(
1682+
Command\RawCommand::create('get', 'key')
1683+
));
1684+
$this->assertSame($slave2, $replication->getCurrent());
1685+
}
1686+
16021687
// ******************************************************************** //
16031688
// ---- HELPER METHODS ------------------------------------------------ //
16041689
// ******************************************************************** //

0 commit comments

Comments
 (0)