diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 29b9b8ec62409..5c2839d74f818 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -81,6 +81,17 @@ jobs: REDIS_MASTER_HOST: redis REDIS_MASTER_SET: redis_sentinel REDIS_SENTINEL_QUORUM: 1 + redis-primary: + image: redis:latest + hostname: redis-primary + ports: + - 16381:6379 + + redis-replica: + image: redis:latest + ports: + - 16382:6379 + command: redis-server --slaveof redis-primary 6379 memcached: image: memcached:1.6.5 ports: @@ -239,6 +250,7 @@ jobs: REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' REDIS_SENTINEL_HOSTS: 'unreachable-host:26379 localhost:26379 localhost:26379' REDIS_SENTINEL_SERVICE: redis_sentinel + REDIS_REPLICATION_HOSTS: 'localhost:16381 localhost:16382' MESSENGER_REDIS_DSN: redis://127.0.0.1:7006/messages MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages MESSENGER_SQS_DSN: "sqs://localhost:4566/messages?sslmode=disable&poll_timeout=0.01" diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisRedisReplicationAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisRedisReplicationAdapterTest.php new file mode 100644 index 0000000000000..552727740c18b --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisRedisReplicationAdapterTest.php @@ -0,0 +1,29 @@ + + * + * 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\RedisAdapter; + +/** + * @group integration + */ +class PredisRedisReplicationAdapterTest extends AbstractRedisAdapterTestCase +{ + public static function setUpBeforeClass(): void + { + if (!$hosts = getenv('REDIS_REPLICATION_HOSTS')) { + self::markTestSkipped('REDIS_REPLICATION_HOSTS env var is not defined.'); + } + + self::$redis = RedisAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).'][alias]=master', ['class' => \Predis\Client::class, 'prefix' => 'prefix_']); + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisReplicationAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisReplicationAdapterTest.php new file mode 100644 index 0000000000000..4add9d5f18c4a --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisReplicationAdapterTest.php @@ -0,0 +1,24 @@ + + * + * 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; + +/** + * @group integration + */ +class PredisReplicationAdapterTest extends AbstractRedisAdapterTestCase +{ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + self::$redis = new \Predis\Client(array_combine(['host', 'port'], explode(':', getenv('REDIS_HOST')) + [1 => 6379]), ['prefix' => 'prefix_']); + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareReplicationAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareReplicationAdapterTest.php new file mode 100644 index 0000000000000..4d8651ce4ceb6 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareReplicationAdapterTest.php @@ -0,0 +1,37 @@ + + * + * 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 Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; + +/** + * @group integration + */ +class PredisTagAwareReplicationAdapterTest extends PredisReplicationAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp(): void + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisReplicationAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisReplicationAdapterTest.php new file mode 100644 index 0000000000000..e41745057f141 --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisReplicationAdapterTest.php @@ -0,0 +1,65 @@ + + * + * 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 Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\Adapter\AbstractAdapter; +use Symfony\Component\Cache\Adapter\RedisAdapter; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Traits\RedisClusterProxy; + +/** + * @group integration + */ +class RedisReplicationAdapterTest extends AbstractRedisAdapterTestCase +{ + public static function setUpBeforeClass(): void + { + if (!$hosts = getenv('REDIS_REPLICATION_HOSTS')) { + self::markTestSkipped('REDIS_REPLICATION_HOSTS env var is not defined.'); + } + + self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).'][alias]=master', ['lazy' => true]); + self::$redis->setOption(\Redis::OPT_PREFIX, 'prefix_'); + } + + public function createCachePool(int $defaultLifetime = 0, ?string $testMethod = null): CacheItemPoolInterface + { + if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) { + self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX); + } + + $this->assertInstanceOf(RedisClusterProxy::class, self::$redis); + $adapter = new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } + + /** + * @dataProvider provideFailedCreateConnection + */ + public function testFailedCreateConnection(string $dsn) + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Redis connection '); + RedisAdapter::createConnection($dsn); + } + + public static function provideFailedCreateConnection(): array + { + return [ + ['redis://localhost:1234'], + ['redis://foo@localhost?role=master'], + ['redis://localhost/123?role=master'], + ]; + } +} diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index fc8f5cec60472..2ebaed16f1804 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -17,6 +17,7 @@ use Predis\Connection\Aggregate\ReplicationInterface; use Predis\Connection\Cluster\ClusterInterface as Predis2ClusterInterface; use Predis\Connection\Cluster\RedisCluster as Predis2RedisCluster; +use Predis\Connection\Replication\ReplicationInterface as Predis2ReplicationInterface; use Predis\Response\ErrorInterface; use Predis\Response\Status; use Relay\Relay; @@ -473,9 +474,16 @@ protected function doClear(string $namespace): bool $cleared = true; $hosts = $this->getHosts(); $host = reset($hosts); - if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) { - // Predis supports info command only on the master in replication environments - $hosts = [$host->getClientFor('master')]; + if ($host instanceof \Predis\Client) { + $connection = $host->getConnection(); + + if ($connection instanceof ReplicationInterface) { + $hosts = [$host->getClientFor('master')]; + } elseif ($connection instanceof Predis2ReplicationInterface) { + $connection->switchToMaster(); + + $hosts = [$host]; + } } foreach ($hosts as $host) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy