[Cache] Add Redis Sentinel support

This commit is contained in:
Stephen Clouse 2019-05-09 01:56:57 -05:00 committed by Nicolas Grekas
parent e19db439d8
commit 80e8b21525
3 changed files with 63 additions and 1 deletions

View File

@ -1,6 +1,11 @@
CHANGELOG
=========
4.4.0
-----
* added support for connecting to Redis Sentinel clusters
4.3.0
-----

View File

@ -0,0 +1,43 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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);
}
}

View File

@ -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 {