diff --git a/src/Symfony/Component/Cache/CHANGELOG.md b/src/Symfony/Component/Cache/CHANGELOG.md index 37dd2e11a0..1d24a97ed8 100644 --- a/src/Symfony/Component/Cache/CHANGELOG.md +++ b/src/Symfony/Component/Cache/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +4.4.0 +----- + + * added support for connecting to Redis Sentinel clusters + 4.3.0 ----- diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php new file mode 100644 index 0000000000..96c942654d --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php @@ -0,0 +1,43 @@ + + * + * 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; + +class RedisAdapterSentinelTest extends AbstractRedisAdapterTest +{ + public static function setupBeforeClass() + { + if (!class_exists('Predis\Client')) { + 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]); + } + + /** + * @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException + * @expectedExceptionMessage Invalid Redis DSN: cannot use both redis_cluster and redis_sentinel at the same time + */ + public function testInvalidDSNHasBothClusterAndSentinel() + { + $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 b2faca651d..6f6d94bbe8 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -38,6 +38,7 @@ trait RedisTrait 'tcp_keepalive' => 0, 'lazy' => null, 'redis_cluster' => false, + 'redis_sentinel' => null, 'dbindex' => 0, 'failover' => 'none', ]; @@ -146,9 +147,13 @@ trait RedisTrait 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 (null === $params['class'] && \extension_loaded('redis')) { + if (null === $params['class'] && !isset($params['redis_sentinel']) && \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']; @@ -246,6 +251,12 @@ trait RedisTrait } elseif (is_a($class, \Predis\Client::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']; } $params += ['parameters' => []]; $params['parameters'] += [ @@ -268,6 +279,9 @@ trait RedisTrait } $redis = new $class($hosts, array_diff_key($params, self::$defaultConnectionOptions)); + if (isset($params['redis_sentinel'])) { + $redis->getConnection()->setSentinelTimeout($params['timeout']); + } } elseif (class_exists($class, false)) { throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster" nor "Predis\Client".', $class)); } else {