Skip to content

Commit

Permalink
Merge pull request shlinkio#83 from acelaya-forks/feature/redis-senti…
Browse files Browse the repository at this point in the history
…nels

Feature/redis sentinels
  • Loading branch information
acelaya authored Oct 8, 2021
2 parents 3eacc46 + 7fdd839 commit 2d87e09
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 13 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).

## [Unreleased]
## [4.0.0] - 2021-10-08
### Added
* *Nothing*
* [#80](https://github.com/shlinkio/shlink-common/issues/80) Added support for redis cache with redis sentinel

### Changed
* [#77](https://github.com/shlinkio/shlink-common/issues/77) Replaced doctrine/cache adapters by symfony/cache, complying with PSR-6 and PSR-16 in the process.
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,14 @@ return [

'cache' => [
'namespace' => 'my_namespace',

'redis' => [
'servers' => [
'tcp://1.1.1.1:6379',
'tcp://2.2.2.2:6379',
'tcp://3.3.3.3:6379',
],
'sentinel_service' => 'theservice' // Optional.
],
],

Expand All @@ -55,7 +57,10 @@ return [

### Redis support

When the `cache.redis` config is provided, a set of servers is expected. If only one server is provided, this library will treat it as a regular server, but if several servers are defined, it will treat them as a redis cluster and expect the servers to be configured as such.
You can allow caching to be done on a redis instance, redis cluster or redis sentinels, by defining some options under `cache.redis` config.

* `servers`: A list of redis servers. If one is provided, it will be treated as a single instance, and otherwise, a cluster will be assumed.
* `sentinel_service`: Lets you enable sentinel mode. When provided, the servers will be treated as sentinel instances.

### Doctrine cache support

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"symfony/translation-contracts": "^2.4"
},
"require-dev": {
"infection/infection": "^0.24",
"infection/infection": "^0.25",
"laminas/laminas-stratigility": "^3.4",
"mezzio/mezzio-problem-details": "^1.4",
"pagerfanta/core": "^2.7",
Expand Down
15 changes: 14 additions & 1 deletion src/Cache/RedisFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,21 @@ public function __invoke(ContainerInterface $container): PredisClient

$servers = $redisConfig['servers'] ?? [];
$servers = is_string($servers) ? explode(',', $servers) : $servers;
$options = count($servers) <= 1 ? null : ['cluster' => 'redis'];
$options = $this->resolveOptions($redisConfig, $servers);

return new PredisClient($servers, $options);
}

private function resolveOptions(array $redisConfig, array $servers): ?array
{
$sentinelService = $redisConfig['sentinel_service'] ?? null;
if ($sentinelService !== null) {
return [
'replication' => 'sentinel',
'service' => $sentinelService,
];
}

return count($servers) <= 1 ? null : ['cluster' => 'redis'];
}
}
26 changes: 18 additions & 8 deletions test/Cache/RedisFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

namespace ShlinkioTest\Shlink\Common\Cache;

use Closure;
use PHPUnit\Framework\TestCase;
use Predis\Connection\Aggregate\MasterSlaveReplication;
use Predis\Connection\Aggregate\PredisCluster;
use Predis\Connection\Aggregate\RedisCluster;
use Prophecy\PhpUnit\ProphecyTrait;
Expand All @@ -29,8 +31,11 @@ public function setUp(): void
* @test
* @dataProvider provideRedisConfig
*/
public function createsRedisClientBasedOnCacheConfig(?array $config, string $expectedCluster): void
{
public function createsRedisClientBasedOnCacheConfig(
?array $config,
string $expectedCluster,
string $expectedReplication,
): void {
$getConfig = $this->container->get('config')->willReturn([
'cache' => [
'redis' => $config,
Expand All @@ -41,25 +46,30 @@ public function createsRedisClientBasedOnCacheConfig(?array $config, string $exp

$getConfig->shouldHaveBeenCalledOnce();
self::assertInstanceOf($expectedCluster, $client->getOptions()->cluster);
self::assertInstanceOf($expectedReplication, $client->getOptions()->replication);
}

public function provideRedisConfig(): iterable
{
yield 'no config' => [null, PredisCluster::class];
yield 'no config' => [null, PredisCluster::class, MasterSlaveReplication::class];
yield 'single server as string' => [[
'servers' => 'tcp://127.0.0.1:6379',
], PredisCluster::class];
], PredisCluster::class, MasterSlaveReplication::class];
yield 'single server as array' => [[
'servers' => ['tcp://127.0.0.1:6379'],
], PredisCluster::class];
], PredisCluster::class, MasterSlaveReplication::class];
yield 'cluster of servers' => [[
'servers' => ['tcp://1.1.1.1:6379', 'tcp://2.2.2.2:6379'],
], RedisCluster::class];
], RedisCluster::class, MasterSlaveReplication::class];
yield 'empty cluster of servers' => [[
'servers' => [],
], PredisCluster::class];
], PredisCluster::class, MasterSlaveReplication::class];
yield 'cluster of servers as string' => [[
'servers' => 'tcp://1.1.1.1:6379,tcp://2.2.2.2:6379',
], RedisCluster::class];
], RedisCluster::class, MasterSlaveReplication::class];
yield 'cluster of sentinels' => [[
'servers' => ['tcp://1.1.1.1:6379', 'tcp://2.2.2.2:6379'],
'sentinel_service' => 'foo',
], PredisCluster::class, Closure::class];
}
}

0 comments on commit 2d87e09

Please sign in to comment.