Skip to content

Commit 80e8b21

Browse files
StephenClousenicolas-grekas
authored andcommitted
[Cache] Add Redis Sentinel support
1 parent e19db43 commit 80e8b21

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-1
lines changed

src/Symfony/Component/Cache/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
4.4.0
5+
-----
6+
7+
* added support for connecting to Redis Sentinel clusters
8+
49
4.3.0
510
-----
611

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache\Tests\Adapter;
13+
14+
use Symfony\Component\Cache\Adapter\AbstractAdapter;
15+
use Symfony\Component\Cache\Adapter\RedisAdapter;
16+
17+
class RedisAdapterSentinelTest extends AbstractRedisAdapterTest
18+
{
19+
public static function setupBeforeClass()
20+
{
21+
if (!class_exists('Predis\Client')) {
22+
self::markTestSkipped('The Predis\Client class is required.');
23+
}
24+
if (!$hosts = getenv('REDIS_SENTINEL_HOSTS')) {
25+
self::markTestSkipped('REDIS_SENTINEL_HOSTS env var is not defined.');
26+
}
27+
if (!$service = getenv('REDIS_SENTINEL_SERVICE')) {
28+
self::markTestSkipped('REDIS_SENTINEL_SERVICE env var is not defined.');
29+
}
30+
31+
self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['redis_sentinel' => $service]);
32+
}
33+
34+
/**
35+
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
36+
* @expectedExceptionMessage Invalid Redis DSN: cannot use both redis_cluster and redis_sentinel at the same time
37+
*/
38+
public function testInvalidDSNHasBothClusterAndSentinel()
39+
{
40+
$dsn = 'redis:?host[redis1]&host[redis2]&host[redis3]&redis_cluster=1&redis_sentinel=mymaster';
41+
RedisAdapter::createConnection($dsn);
42+
}
43+
}

src/Symfony/Component/Cache/Traits/RedisTrait.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ trait RedisTrait
3838
'tcp_keepalive' => 0,
3939
'lazy' => null,
4040
'redis_cluster' => false,
41+
'redis_sentinel' => null,
4142
'dbindex' => 0,
4243
'failover' => 'none',
4344
];
@@ -146,9 +147,13 @@ public static function createConnection($dsn, array $options = [])
146147
throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn));
147148
}
148149

150+
if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class)) {
151+
throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package: %s', $dsn));
152+
}
153+
149154
$params += $query + $options + self::$defaultConnectionOptions;
150155

151-
if (null === $params['class'] && \extension_loaded('redis')) {
156+
if (null === $params['class'] && !isset($params['redis_sentinel']) && \extension_loaded('redis')) {
152157
$class = $params['redis_cluster'] ? \RedisCluster::class : (1 < \count($hosts) ? \RedisArray::class : \Redis::class);
153158
} else {
154159
$class = null === $params['class'] ? \Predis\Client::class : $params['class'];
@@ -246,6 +251,12 @@ public static function createConnection($dsn, array $options = [])
246251
} elseif (is_a($class, \Predis\Client::class, true)) {
247252
if ($params['redis_cluster']) {
248253
$params['cluster'] = 'redis';
254+
if (isset($params['redis_sentinel'])) {
255+
throw new InvalidArgumentException(sprintf('Cannot use both "redis_cluster" and "redis_sentinel" at the same time: %s', $dsn));
256+
}
257+
} elseif (isset($params['redis_sentinel'])) {
258+
$params['replication'] = 'sentinel';
259+
$params['service'] = $params['redis_sentinel'];
249260
}
250261
$params += ['parameters' => []];
251262
$params['parameters'] += [
@@ -268,6 +279,9 @@ public static function createConnection($dsn, array $options = [])
268279
}
269280

270281
$redis = new $class($hosts, array_diff_key($params, self::$defaultConnectionOptions));
282+
if (isset($params['redis_sentinel'])) {
283+
$redis->getConnection()->setSentinelTimeout($params['timeout']);
284+
}
271285
} elseif (class_exists($class, false)) {
272286
throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster" nor "Predis\Client".', $class));
273287
} else {

0 commit comments

Comments
 (0)