From 9caebe5f164ac0ee195b122b663fe4e5993aedc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Renan=20Gon=C3=A7alves?= Date: Mon, 7 Dec 2020 15:08:24 +0100 Subject: [PATCH 1/3] Support Redis Sentinel mode when using phpredis/phpredis extension The version 5.2.0 of the [Redis PHP extension](http://pecl.php.net/package/redis), released back in March 2020, added support for Redis Sentinel mode with the help of the `RedisSentinel` class. Usage of the `Symfony/Cache RedisAdapter` can continue to be the same, thus relying on the `$options['redis_persistent']` option to both enable and define the master name. --- src/Symfony/Component/Cache/CHANGELOG.md | 5 +++ .../Adapter/PredisAdapterSentinelTest.php | 44 +++++++++++++++++++ .../Adapter/RedisAdapterSentinelTest.php | 4 +- .../Component/Cache/Traits/RedisTrait.php | 31 +++++++++---- 4 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterSentinelTest.php diff --git a/src/Symfony/Component/Cache/CHANGELOG.md b/src/Symfony/Component/Cache/CHANGELOG.md index 73965c205890..2b6c4b177cee 100644 --- a/src/Symfony/Component/Cache/CHANGELOG.md +++ b/src/Symfony/Component/Cache/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +5.3.0 +----- + +* added support for connecting to Redis Sentinel clusters when using the Redis PHP extension + 5.2.0 ----- diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterSentinelTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterSentinelTest.php new file mode 100644 index 000000000000..bc01737fd3d0 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterSentinelTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Adapter; + +use Symfony\Component\Cache\Adapter\AbstractAdapter; +use Symfony\Component\Cache\Adapter\RedisAdapter; + +/** + * @group integration + */ +class PredisAdapterSentinelTest extends AbstractRedisAdapterTest +{ + public static function setUpBeforeClass(): void + { + if (!class_exists(\Predis\Client::class)) { + self::markTestSkipped('The Predis\Client class is required.'); + } + if (!$hosts = getenv('REDIS_SENTINEL_HOSTS')) { + self::markTestSkipped('REDIS_SENTINEL_HOSTS env var is not defined.'); + } + if (!$service = getenv('REDIS_SENTINEL_SERVICE')) { + self::markTestSkipped('REDIS_SENTINEL_SERVICE env var is not defined.'); + } + + self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['redis_sentinel' => $service, 'class' => \Predis\Client::class]); + } + + public function testInvalidDSNHasBothClusterAndSentinel() + { + $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); + $this->expectExceptionMessage('Cannot use both "redis_cluster" and "redis_sentinel" at the same time:'); + $dsn = 'redis:?host[redis1]&host[redis2]&host[redis3]&redis_cluster=1&redis_sentinel=mymaster'; + RedisAdapter::createConnection($dsn); + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php index 82b9f08b6547..84ea7969ad96 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php @@ -21,8 +21,8 @@ class RedisAdapterSentinelTest extends AbstractRedisAdapterTest { public static function setUpBeforeClass(): void { - if (!class_exists('Predis\Client')) { - self::markTestSkipped('The Predis\Client class is required.'); + if (!class_exists(\RedisSentinel::class)) { + self::markTestSkipped('The RedisSentinel class is required.'); } if (!$hosts = getenv('REDIS_SENTINEL_HOSTS')) { self::markTestSkipped('REDIS_SENTINEL_HOSTS env var is not defined.'); diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 317879aa494e..ef70bf786e78 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -159,13 +159,17 @@ public static function createConnection($dsn, array $options = []) throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn)); } - if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class)) { - throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package: "%s".', $dsn)); + $params += $query + $options + self::$defaultConnectionOptions; + + if (isset($params['redis_sentinel']) && (!class_exists(\Predis\Client::class) || !class_exists(\RedisSentinel::class))) { + throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package or the "redis" extension with minimum version v5.2.0: "%s".', $dsn)); } - $params += $query + $options + self::$defaultConnectionOptions; + if ($params['redis_cluster'] && isset($params['redis_sentinel'])) { + throw new InvalidArgumentException(sprintf('Cannot use both "redis_cluster" and "redis_sentinel" at the same time: "%s".', $dsn)); + } - if (null === $params['class'] && !isset($params['redis_sentinel']) && \extension_loaded('redis')) { + if (null === $params['class'] && \extension_loaded('redis')) { $class = $params['redis_cluster'] ? \RedisCluster::class : (1 < \count($hosts) ? \RedisArray::class : \Redis::class); } else { $class = null === $params['class'] ? \Predis\Client::class : $params['class']; @@ -176,8 +180,22 @@ public static function createConnection($dsn, array $options = []) $redis = new $class(); $initializer = static function ($redis) use ($connect, $params, $dsn, $auth, $hosts) { + $address = $hosts[0]['host'] ?? $hosts[0]['path']; + $port = $hosts[0]['port'] ?? null; + + if (isset($params['redis_sentinel'])) { + $sentinel = new \RedisSentinel($address, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); + $master = $sentinel->getMasterAddrByName($params['redis_sentinel']); + if (false === $master) { + throw new InvalidArgumentException(sprintf('Failed to retrieve master information from master name "%s" and address "%s:%d".', $params['redis_sentinel'], $address, $port)); + } + + $address = $master[0]; + $port = $master[1]; + } + try { - @$redis->{$connect}($hosts[0]['host'] ?? $hosts[0]['path'], $hosts[0]['port'] ?? null, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); + @$redis->{$connect}($address, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); $isConnected = $redis->isConnected(); @@ -254,9 +272,6 @@ public static function createConnection($dsn, array $options = []) } elseif (is_a($class, \Predis\ClientInterface::class, true)) { if ($params['redis_cluster']) { $params['cluster'] = 'redis'; - if (isset($params['redis_sentinel'])) { - throw new InvalidArgumentException(sprintf('Cannot use both "redis_cluster" and "redis_sentinel" at the same time: "%s".', $dsn)); - } } elseif (isset($params['redis_sentinel'])) { $params['replication'] = 'sentinel'; $params['service'] = $params['redis_sentinel']; From ba6bb87402aaec6555c25cc7a79266195f72baf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Renan=20Gon=C3=A7alves?= Date: Tue, 8 Dec 2020 10:41:27 +0100 Subject: [PATCH 2/3] fixup! Support Redis Sentinel mode when using phpredis/phpredis extension --- .../Tests/Adapter/PredisAdapterSentinelTest.php | 9 --------- .../Component/Cache/Traits/RedisTrait.php | 17 +++++++---------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterSentinelTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterSentinelTest.php index bc01737fd3d0..e6de9b3ee6bb 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterSentinelTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterSentinelTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Cache\Tests\Adapter; use Symfony\Component\Cache\Adapter\AbstractAdapter; -use Symfony\Component\Cache\Adapter\RedisAdapter; /** * @group integration @@ -33,12 +32,4 @@ public static function setUpBeforeClass(): void self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['redis_sentinel' => $service, 'class' => \Predis\Client::class]); } - - public function testInvalidDSNHasBothClusterAndSentinel() - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Cannot use both "redis_cluster" and "redis_sentinel" at the same time:'); - $dsn = 'redis:?host[redis1]&host[redis2]&host[redis3]&redis_cluster=1&redis_sentinel=mymaster'; - RedisAdapter::createConnection($dsn); - } } diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index ef70bf786e78..f0a61292be3e 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -162,7 +162,7 @@ public static function createConnection($dsn, array $options = []) $params += $query + $options + self::$defaultConnectionOptions; if (isset($params['redis_sentinel']) && (!class_exists(\Predis\Client::class) || !class_exists(\RedisSentinel::class))) { - throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package or the "redis" extension with minimum version v5.2.0: "%s".', $dsn)); + throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package or the "redis" extension v5.2 or higher: "%s".', $dsn)); } if ($params['redis_cluster'] && isset($params['redis_sentinel'])) { @@ -180,22 +180,19 @@ public static function createConnection($dsn, array $options = []) $redis = new $class(); $initializer = static function ($redis) use ($connect, $params, $dsn, $auth, $hosts) { - $address = $hosts[0]['host'] ?? $hosts[0]['path']; + $host = $hosts[0]['host'] ?? $hosts[0]['path']; $port = $hosts[0]['port'] ?? null; if (isset($params['redis_sentinel'])) { - $sentinel = new \RedisSentinel($address, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); - $master = $sentinel->getMasterAddrByName($params['redis_sentinel']); - if (false === $master) { - throw new InvalidArgumentException(sprintf('Failed to retrieve master information from master name "%s" and address "%s:%d".', $params['redis_sentinel'], $address, $port)); - } + $sentinel = new \RedisSentinel($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); - $address = $master[0]; - $port = $master[1]; + if (!([$host, $port] = $sentinel->getMasterAddrByName($params['redis_sentinel']))) { + throw new InvalidArgumentException(sprintf('Failed to retrieve master information from master name "%s" and address "%s:%d".', $params['redis_sentinel'], $host, $port)); + } } try { - @$redis->{$connect}($address, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); + @$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); $isConnected = $redis->isConnected(); From c3086f77d481c179e552033b43f6ae46aec09b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Renan=20Gon=C3=A7alves?= Date: Tue, 8 Dec 2020 11:32:59 +0100 Subject: [PATCH 3/3] fixup! Support Redis Sentinel mode when using phpredis/phpredis extension --- src/Symfony/Component/Cache/Traits/RedisTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index f0a61292be3e..6e6b6d0e4f6c 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -186,7 +186,7 @@ public static function createConnection($dsn, array $options = []) if (isset($params['redis_sentinel'])) { $sentinel = new \RedisSentinel($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); - if (!([$host, $port] = $sentinel->getMasterAddrByName($params['redis_sentinel']))) { + if (![$host, $port] = $sentinel->getMasterAddrByName($params['redis_sentinel'])) { throw new InvalidArgumentException(sprintf('Failed to retrieve master information from master name "%s" and address "%s:%d".', $params['redis_sentinel'], $host, $port)); } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy