8000 [Cache] Add RedisProxy for lazy Redis connections · symfony/symfony@778abd8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 778abd8

Browse files
[Cache] Add RedisProxy for lazy Redis connections
1 parent a3e0e49 commit 778abd8

File tree

6 files changed

+101
-22
lines changed

6 files changed

+101
-22
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public static function getServiceProvider(ContainerBuilder $container, $name)
134134
$definition = new Definition(AbstractAdapter::class);
135135
$definition->setPublic(false);
136136
$definition->setFactory(array(AbstractAdapter::class, 'createConnection'));
137-
$definition->setArguments(array($dsn));
137+
$definition->setArguments(array($dsn, array('lazy' => true')));
138138
$container->setDefinition($name, $definition);
139139
}
140140
}

src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ public function testCreateConnection()
4444
'persistent_id' => null,
4545
'read_timeout' => 0,
4646
'retry_interval' => 0,
47+
'lazy' => false,
4748
'database' => '1',
4849
'password' => null,
4950
);

src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,22 @@
1313

1414
use Symfony\Component\Cache\Adapter\AbstractAdapter;
1515
use Symfony\Component\Cache\Adapter\RedisAdapter;
16+
use Symfony\Component\Cache\Traits\RedisProxy;
1617

1718
class RedisAdapterTest extends AbstractRedisAdapterTest
1819
{
1920
public static function setupBeforeClass()
2021
{
2122
parent::setupBeforeClass();
22-
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'));
23+
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), array('lazy' => true));
24+
}
25+
26+
public function createCachePool($defaultLifetime = 0)
27+
{
28+
$adapter = parent::createCachePool($defaultLifetime);
29+
$this->assertInstanceOf(RedisProxy::class, self::$redis);
30+
31+
return $adapter;
2332
}
2433

2534
public function testCreateConnection()
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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\Traits;
13+
14+
/**
15+
* @author Nicolas Grekas <p@tchwork.com>
16+
*
17+
* @internal
18+
*/
19+
class RedisProxy
20+
{
21+
private $redis;
22+
private $initializer;
23+
private $ready = false;
24+
25+
public function __construct(\Redis $redis, \Closure $initializer)
26+
{
27+
$this->redis = $redis;
28+
$this->initializer = $initializer;
29+
}
30+
31+
public function __call($method, array $args)
32+
{
33+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
34+
35+
return \call_user_func_array(array($this->redis, $method), $args);
36+
}
37+
38+
public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
39+
{
40+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
41+
42+
return $this->redis->hscan($strKey, $iIterator, $strPattern, $iCount);
43+
}
44+
45+
public function scan(&$iIterator, $strPattern = null, $iCount = null)
46+
{
47+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
48+
49+
return $this->redis->scan($iIterator, $strPattern, $iCount);
50+
}
51+
52+
public function sscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
53+
{
54+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
55+
56+
return $this->redis->sscan($strKey, $iIterator, $strPattern, $iCount);
57+
}
58+
59+
public function zscan($strKey, &$iIterator, $strPattern = null, $iCount = null)
60+
{
61+
$this->ready ?: $this->ready = $this->initializer->__invoke($this->redis);
62+
63+
return $this->redis->zscan($strKey, $iIterator, $strPattern, $iCount);
64+
}
65+
}

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

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ trait RedisTrait
3434
'timeout' => 30,
3535
'read_timeout' => 0,
3636
'retry_interval' => 0,
37+
'lazy' => false,
3738
);
3839
private $redis;
3940

@@ -49,7 +50,7 @@ public function init($redisClient, $namespace = '', $defaultLifetime = 0)
4950
}
5051
if ($redisClient instanceof \RedisCluster) {
5152
$this->enableVersioning();
52-
} elseif (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \Predis\Client) {
53+
} elseif (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) {
5354
throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, is_object($redisClient) ? get_class($redisClient) : gettype($redisClient)));
5455
}
5556
$this->redis = $redisClient;
@@ -117,19 +118,30 @@ public static function createConnection($dsn, array $options = array())
117118
if (is_a($class, \Redis::class, true)) {
118119
$connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect';
119120
$redis = new $class();
120-
@$redis->{$connect}($params['host'], $params['port'], $params['timeout'], $params['persistent_id'], $params['retry_interval']);
121121

122-
if (@!$redis->isConnected()) {
123-
$e = ($e = error_get_last()) && preg_match('/^Redis::p?connect\(\): (.*)/', $e['message'], $e) ? sprintf(' (%s)', $e[1]) : '';
124-
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $e, $dsn));
125-
}
122+
$initializer = function ($redis) use ($connect, $params, $dsn, $auth) {
123+
@$redis->{$connect}($params['host'], $params['port'], $params['timeout'], $params['persistent_id'], $params['retry_interval']);
124+
125+
if (@!$redis->isConnected()) {
126+
$e = ($e = error_get_last()) && preg_match('/^Redis::p?connect\(\): (.*)/', $e['message'], $e) ? sprintf(' (%s)', $e[1]) : '';
127+
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $e, $dsn));
128+
}
129+
130+
if ((null !== $auth && !$redis->auth($auth))
131+
|| ($params['dbindex'] && !$redis->select($params['dbindex']))
132+
|| ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout']))
133+
) {
134+
$e = preg_replace('/^ERR /', '', $redis->getLastError());
135+
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn));
136+
}
137+
138+
return true;
139+
};
126140

127-
if ((null !== $auth && !$redis->auth($auth))
128-
|| ($params['dbindex'] && !$redis->select($params['dbindex']))
129-
|| ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout']))
130-
) {
131-
$e = preg_replace('/^ERR /', '', $redis->getLastError());
132-
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn));
141+
if ($params['lazy']) {
142+
$redis = new RedisProxy($redis, $initializer);
143+
} else {
144+
$initializer($redis);
133145
}
134146
} elseif (is_a($class, \Predis\Client::class, true)) {
135147
$params['scheme'] = $scheme;

src/Symfony/Component/Lock/Store/RedisStore.php

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,6 @@
2424
*/
2525
class RedisStore implements StoreInterface
2626
{
27-
private static $defaultConnectionOptions = array(
28-
'class' => null,
29-
'persistent' => 0,
30-
'persistent_id' => null,
31-
'timeout' => 30,
32-
'read_timeout' => 0,
33-
'retry_interval' => 0,
34-
);
3527
private $redis;
3628
private $initialTtl;
3729

0 commit comments

Comments
 (0)
0