Skip to content

Commit

Permalink
[Cache] Add Relay support
Browse files Browse the repository at this point in the history
  • Loading branch information
ostrolucky committed Jan 24, 2023
1 parent 767e0f9 commit 4173c38
Show file tree
Hide file tree
Showing 12 changed files with 1,478 additions and 43 deletions.
1 change: 1 addition & 0 deletions .github/patch-types.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/ReflectionIntersectionTypeFixture.php'):
case false !== strpos($file, '/src/Symfony/Component/VarDumper/Tests/Fixtures/ReflectionUnionTypeWithIntersectionFixture.php'):
case false !== strpos($file, '/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyProxy/ReadOnlyClass.php'):
case false !== strpos($file, '/src/Symfony/Component/Cache/Traits/RelayProxy.php'):
continue 2;
}

Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,19 @@ jobs:
uses: shivammathur/setup-php@v2
with:
coverage: "none"
extensions: "json,couchbase-3.2.2,memcached,mongodb-1.12.0,redis,rdkafka,xsl,ldap"
extensions: "json,couchbase-3.2.2,memcached,mongodb-1.12.0,redis,rdkafka,xsl,ldap,msgpack,igbinary"
ini-values: date.timezone=UTC,memory_limit=-1,default_socket_timeout=10,session.gc_probability=0,apc.enable_cli=1,zend.assertions=1
php-version: "${{ matrix.php }}"
tools: pecl

- name: Install Relay
run: |
curl -L "https://builds.r2.relay.so/dev/relay-dev-php${{ matrix.php }}-debian-x86-64.tar.gz" | tar xz
cd relay-dev-php${{ matrix.php }}-debian-x86-64
sudo cp relay.ini $(php-config --ini-dir)
sudo cp relay-pkg.so $(php-config --extension-dir)/relay.so
sudo sed -i "s/00000000-0000-0000-0000-000000000000/$(cat /proc/sys/kernel/random/uuid)/" $(php-config --extension-dir)/relay.so
- name: Display versions
run: |
php -r 'foreach (get_loaded_extensions() as $extension) echo $extension . " " . phpversion($extension) . PHP_EOL;'
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/psalm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ jobs:
ini-values: "memory_limit=-1"
coverage: none

- name: Install Relay
run: |
curl -L "https://builds.r2.relay.so/dev/relay-dev-php8.1-debian-x86-64.tar.gz" | tar xz
cd relay-dev-php8.1-debian-x86-64
sudo cp relay.ini $(php-config --ini-dir)
sudo cp relay-pkg.so $(php-config --extension-dir)/relay.so
sudo sed -i "s/00000000-0000-0000-0000-000000000000/$(cat /proc/sys/kernel/random/uuid)/" $(php-config --extension-dir)/relay.so
- name: Checkout target branch
uses: actions/checkout@v3
with:
Expand Down
1 change: 1 addition & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
// stop removing spaces on the end of the line in strings
->notPath('Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php')
// auto-generated proxies
->notPath('Symfony/Component/Cache/Traits/RelayProxy.php')
->notPath('Symfony/Component/Cache/Traits/Redis5Proxy.php')
->notPath('Symfony/Component/Cache/Traits/Redis6Proxy.php')
->notPath('Symfony/Component/Cache/Traits/RedisCluster5Proxy.php')
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/Cache/Adapter/RedisAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class RedisAdapter extends AbstractAdapter
{
use RedisTrait;

public function __construct(\Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
public function __construct(\Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|\Relay\Relay $redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
{
$this->init($redis, $namespace, $defaultLifetime, $marshaller);
}
Expand Down
18 changes: 10 additions & 8 deletions src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Response\ErrorInterface;
use Predis\Response\Status;
use Relay\Relay;
use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Exception\LogicException;
Expand Down Expand Up @@ -59,18 +60,19 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter
private string $redisEvictionPolicy;
private string $namespace;

public function __construct(\Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
public function __construct(\Redis|Relay|\RedisArray|\RedisCluster|\Predis\ClientInterface $redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null)
{
if ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof ClusterInterface && !$redis->getConnection() instanceof PredisCluster) {
throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, get_debug_type($redis->getConnection())));
}

if (\defined('Redis::OPT_COMPRESSION') && \in_array($redis::class, [\Redis::class, \RedisArray::class, \RedisCluster::class], true)) {
$compression = $redis->getOption(\Redis::OPT_COMPRESSION);
$isRelay = $redis instanceof Relay;
if ($isRelay || \defined('Redis::OPT_COMPRESSION') && \in_array($redis::class, [\Redis::class, \RedisArray::class, \RedisCluster::class], true)) {
$compression = $redis->getOption($isRelay ? Relay::OPT_COMPRESSION : \Redis::OPT_COMPRESSION);

foreach (\is_array($compression) ? $compression : [$compression] as $c) {
if (\Redis::COMPRESSION_NONE !== $c) {
throw new InvalidArgumentException(sprintf('phpredis compression must be disabled when using "%s", use "%s" instead.', static::class, DeflateMarshaller::class));
if ($isRelay ? Relay::COMPRESSION_NONE : \Redis::COMPRESSION_NONE !== $c) {
throw new InvalidArgumentException(sprintf('redis compression must be disabled when using "%s", use "%s" instead.', static::class, DeflateMarshaller::class));
}
}
}
Expand Down Expand Up @@ -154,7 +156,7 @@ protected function doDeleteYieldTags(array $ids): iterable
});

foreach ($results as $id => $result) {
if ($result instanceof \RedisException || $result instanceof ErrorInterface) {
if ($result instanceof \RedisException || $result instanceof \Relay\Exception || $result instanceof ErrorInterface) {
CacheItem::log($this->logger, 'Failed to delete key "{key}": '.$result->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $result]);

continue;
Expand Down Expand Up @@ -221,7 +223,7 @@ protected function doInvalidate(array $tagIds): bool
$results = $this->pipeline(function () use ($tagIds, $lua) {
if ($this->redis instanceof \Predis\ClientInterface) {
$prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : '';
} elseif (\is_array($prefix = $this->redis->getOption(\Redis::OPT_PREFIX) ?? '')) {
} elseif (\is_array($prefix = $this->redis->getOption($this->redis instanceof Relay ? Relay::OPT_PREFIX : \Redis::OPT_PREFIX) ?? '')) {
$prefix = current($prefix);
}

Expand All @@ -242,7 +244,7 @@ protected function doInvalidate(array $tagIds): bool

$success = true;
foreach ($results as $id => $values) {
if ($values instanceof \RedisException || $values instanceof ErrorInterface) {
if ($values instanceof \RedisException || $values instanceof \Relay\Exception || $values instanceof ErrorInterface) {
CacheItem::log($this->logger, 'Failed to invalidate key "{key}": '.$values->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $values]);
$success = false;

Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/Cache/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

6.3
---

* Add support for Relay PHP extension for Redis

6.1
---

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* 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 PHPUnit\Framework\SkippedTestSuiteError;
use Relay\Relay;
use Relay\Sentinel;
use Symfony\Component\Cache\Adapter\AbstractAdapter;

/**
* @group integration
*/
class RelayAdapterSentinelTest extends AbstractRedisAdapterTest
{
public static function setUpBeforeClass(): void
{
if (!class_exists(Sentinel::class)) {
throw new SkippedTestSuiteError('The Relay\Sentinel class is required.');
}
if (!$hosts = getenv('REDIS_SENTINEL_HOSTS')) {
throw new SkippedTestSuiteError('REDIS_SENTINEL_HOSTS env var is not defined.');
}
if (!$service = getenv('REDIS_SENTINEL_SERVICE')) {
throw new SkippedTestSuiteError('REDIS_SENTINEL_SERVICE env var is not defined.');
}

self::$redis = AbstractAdapter::createConnection(
'redis:?host['.str_replace(' ', ']&host[', $hosts).']',
['redis_sentinel' => $service, 'prefix' => 'prefix_', 'class' => Relay::class],
);
self::assertInstanceOf(Relay::class, self::$redis);
}
}
56 changes: 56 additions & 0 deletions src/Symfony/Component/Cache/Tests/Adapter/RelayAdapterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* 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 PHPUnit\Framework\SkippedTestSuiteError;
use Relay\Relay;
use Symfony\Component\Cache\Adapter\AbstractAdapter;
use Symfony\Component\Cache\Adapter\RedisAdapter;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Traits\RelayProxy;

/**
* @requires extension relay
*
* @group integration
*/
class RelayAdapterTest extends AbstractRedisAdapterTest
{
public static function setUpBeforeClass(): void
{
try {
new Relay(...explode(':', getenv('REDIS_HOST')));
} catch (\Relay\Exception $e) {
throw new SkippedTestSuiteError(getenv('REDIS_HOST').': '.$e->getMessage());
}
self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), ['lazy' => true, 'class' => Relay::class]);
self::assertInstanceOf(RelayProxy::class, self::$redis);
}

public function testCreateHostConnection()
{
$redis = RedisAdapter::createConnection('redis://'.getenv('REDIS_HOST').'?class=Relay\Relay');
$this->assertInstanceOf(Relay::class, $redis);
$this->assertTrue($redis->isConnected());
$this->assertSame(0, $redis->getDbNum());
}

public function testLazyConnection()
{
$redis = RedisAdapter::createConnection('redis://nonexistenthost?class=Relay\Relay&lazy=1');
$this->assertInstanceOf(RelayProxy::class, $redis);
// no exception until now
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Failed to resolve host address');
$redis->getHost(); // yep, only here exception is thrown
}
}
36 changes: 33 additions & 3 deletions src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@
namespace Symfony\Component\Cache\Tests\Traits;

use PHPUnit\Framework\TestCase;
use Relay\Relay;
use Symfony\Component\VarExporter\LazyProxyTrait;
use Symfony\Component\VarExporter\ProxyHelper;

/**
* @requires extension redis
*/
class RedisProxiesTest extends TestCase
{
/**
* @requires extension redis
*
* @testWith ["Redis"]
* ["RedisCluster"]
*/
Expand Down Expand Up @@ -50,6 +50,36 @@ public function testRedis5Proxy($class)
}

/**
* @requires extension relay
*/
public function testRelayProxy()
{
$proxy = file_get_contents(\dirname(__DIR__, 2).'/Traits/RelayProxy.php');
$proxy = substr($proxy, 0, 8 + strpos($proxy, "\n ];"));
$methods = [];

foreach ((new \ReflectionClass(Relay::class))->getMethods() as $method) {
if ('reset' === $method->name || method_exists(LazyProxyTrait::class, $method->name) || $method->isStatic()) {
continue;
}
$return = $method->getReturnType() instanceof \ReflectionNamedType && 'void' === (string) $method->getReturnType() ? '' : 'return ';
$methods[] = "\n ".ProxyHelper::exportSignature($method, false)."\n".<<<EOPHP
{
{$return}\$this->lazyObjectReal->{$method->name}(...\\func_get_args());
}
EOPHP;
}

uksort($methods, 'strnatcmp');
$proxy .= implode('', $methods)."}\n";

$this->assertStringEqualsFile(\dirname(__DIR__, 2).'/Traits/RelayProxy.php', $proxy);
}

/**
* @requires extension redis
*
* @testWith ["Redis", "redis"]
* ["RedisCluster", "redis_cluster"]
*/
Expand Down
Loading

0 comments on commit 4173c38

Please sign in to comment.