Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Redis] Add ability to pass Redis instance to connection factory #372

Merged
merged 3 commits into from
Feb 15, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions bin/dev
Original file line number Diff line number Diff line change
@@ -6,13 +6,13 @@ set -e
while getopts "bustefcdp" OPTION; do
case $OPTION in
b)
COMPOSE_PROJECT_NAME=mqdev docker-compose pull && COMPOSE_PROJECT_NAME=mqdev docker-compose build
docker-compose pull && docker-compose build
;;
u)
COMPOSE_PROJECT_NAME=mqdev docker-compose up
docker-compose up
;;
s)
COMPOSE_PROJECT_NAME=mqdev docker-compose stop
docker-compose stop
;;
e)
docker exec -it mqdev_dev_1 /bin/bash
@@ -24,10 +24,10 @@ while getopts "bustefcdp" OPTION; do
./bin/run-fun-test.sh "$2"
;;
c)
COMPOSE_PROJECT_NAME=mqdev docker-compose run -e CHANGELOG_GITHUB_TOKEN=${CHANGELOG_GITHUB_TOKEN:-""} --workdir="/mqdev" --rm generate-changelog github_changelog_generator --future-release "$2" --simple-list
docker-compose run -e CHANGELOG_GITHUB_TOKEN=${CHANGELOG_GITHUB_TOKEN:-""} --workdir="/mqdev" --rm generate-changelog github_changelog_generator --future-release "$2" --simple-list
;;

d) COMPOSE_PROJECT_NAME=mqdev docker-compose run --workdir="/mqdev" --rm dev php pkg/enqueue-bundle/Tests/Functional/app/console.php config:dump-reference enqueue -vvv
d) docker-compose run --workdir="/mqdev" --rm dev php pkg/enqueue-bundle/Tests/Functional/app/console.php config:dump-reference enqueue -vvv
;;
\?)
echo "Invalid option: -$OPTARG" >&2
17 changes: 17 additions & 0 deletions docs/transport/redis.md
Original file line number Diff line number Diff line change
@@ -78,6 +78,23 @@ $connectionFactory = new RedisConnectionFactory([
$psrContext = $connectionFactory->createContext();
```

* With custom redis instance:

It gives you more control over vendor specific features.

```php
<?php
use Enqueue\Redis\RedisConnectionFactory;
use Enqueue\Redis\PRedis;

$config = [];
$options = [];

$redis = new PRedis(new \PRedis\Client($config, $options));

$factory = new RedisConnectionFactory(['vendor' => 'custom', 'redis' => $redis]);
```

## Send message to topic

```php
16 changes: 15 additions & 1 deletion pkg/redis/RedisConnectionFactory.php
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ class RedisConnectionFactory implements PsrConnectionFactory
* 'reserved' => should be null if $retry_interval is specified
* 'retry_interval' => retry interval in milliseconds.
* 'vendor' => 'The library used internally to interact with Redis server
* 'redis' => 'Used only if vendor is custom, should contain an instance of \Enqueue\Redis\Redis interface.
* 'persisted' => bool, Whether it use single persisted connection or open a new one for every context
* 'lazy' => the connection will be performed as later as possible, if the option set to true
* 'database' => Database index to select when connected (default value: 0)
@@ -50,7 +51,7 @@ public function __construct($config = 'redis:')

$this->config = array_replace($this->defaultConfig(), $config);

$supportedVendors = ['predis', 'phpredis'];
$supportedVendors = ['predis', 'phpredis', 'custom'];
if (false == in_array($this->config['vendor'], $supportedVendors, true)) {
throw new \LogicException(sprintf(
'Unsupported redis vendor given. It must be either "%s". Got "%s"',
@@ -90,6 +91,18 @@ private function createRedis()
$this->redis = new PRedis(new Client($this->config, ['exceptions' => true]));
}

if ('custom' == $this->config['vendor'] && false == $this->redis) {
if (empty($this->config['redis'])) {
throw new \LogicException('The redis option should be set if vendor is custom.');
}

if (false == $this->config['redis'] instanceof Redis) {
throw new \LogicException(sprintf('The redis option should be instance of "%s".', Redis::class));
}

$this->redis = $this->config['redis'];
}

$this->redis->connect();
}

@@ -138,6 +151,7 @@ private function defaultConfig()
'reserved' => null,
'retry_interval' => null,
'vendor' => 'phpredis',
'redis' => null,
'persisted' => false,
'lazy' => true,
'database' => 0,
10 changes: 9 additions & 1 deletion pkg/redis/Symfony/RedisTransportFactory.php
Original file line number Diff line number Diff line change
@@ -49,10 +49,14 @@ public function addConfiguration(ArrayNodeDefinition $builder)
->end()
->integerNode('port')->end()
->enumNode('vendor')
->values(['phpredis', 'predis'])
->values(['phpredis', 'predis', 'custom'])
->cannotBeEmpty()
->info('The library used internally to interact with Redis server')
->end()
->scalarNode('redis')
->cannotBeEmpty()
->info('A custom redis service id, used with vendor true only')
->end()
->booleanNode('persisted')
->defaultFalse()
->info('bool, Whether it use single persisted connection or open a new one for every context')
@@ -73,6 +77,10 @@ public function addConfiguration(ArrayNodeDefinition $builder)
*/
public function createConnectionFactory(ContainerBuilder $container, array $config)
{
if (false == empty($config['redis'])) {
$config['redis'] = new Reference($config['redis']);
}

$factory = new Definition(RedisConnectionFactory::class);
$factory->setArguments([isset($config['dsn']) ? $config['dsn'] : $config]);

7 changes: 6 additions & 1 deletion pkg/redis/Tests/RedisConnectionFactoryConfigTest.php
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ public function testThrowIfDsnCouldNotBeParsed()
public function testThrowIfVendorIsInvalid()
{
$this->expectException(\LogicException::class);
$this->expectExceptionMessage('Unsupported redis vendor given. It must be either "predis", "phpredis". Got "invalidVendor"');
$this->expectExceptionMessage('Unsupported redis vendor given. It must be either "predis", "phpredis", "custom". Got "invalidVendor"');

new RedisConnectionFactory(['vendor' => 'invalidVendor']);
}
@@ -72,6 +72,7 @@ public static function provideConfigs()
'persisted' => false,
'lazy' => true,
'database' => 0,
'redis' => null,
],
];

@@ -87,6 +88,7 @@ public static function provideConfigs()
'persisted' => false,
'lazy' => true,
'database' => 0,
'redis' => null,
],
];

@@ -102,6 +104,7 @@ public static function provideConfigs()
'persisted' => false,
'lazy' => true,
'database' => 0,
'redis' => null,
],
];

@@ -118,6 +121,7 @@ public static function provideConfigs()
'lazy' => false,
'foo' => 'bar',
'database' => 5,
'redis' => null,
],
];

@@ -134,6 +138,7 @@ public static function provideConfigs()
'lazy' => true,
'foo' => 'bar',
'database' => 0,
'redis' => null,
],
];
}
42 changes: 42 additions & 0 deletions pkg/redis/Tests/RedisConnectionFactoryTest.php
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

namespace Enqueue\Redis\Tests;

use Enqueue\Redis\Redis;
use Enqueue\Redis\RedisConnectionFactory;
use Enqueue\Redis\RedisContext;
use Enqueue\Test\ClassExtensionTrait;
@@ -28,4 +29,45 @@ public function testShouldCreateLazyContext()
$this->assertAttributeEquals(null, 'redis', $context);
$this->assertInternalType('callable', $this->readAttribute($context, 'redisFactory'));
}

public function testShouldThrowIfVendorIsCustomButRedisInstanceNotSet()
{
$factory = new RedisConnectionFactory([
'vendor' => 'custom',
'redis' => null,
'lazy' => false,
]);

$this->expectException(\LogicException::class);
$this->expectExceptionMessage('The redis option should be set if vendor is custom.');
$factory->createContext();
}

public function testShouldThrowIfVendorIsCustomButRedisIsNotInstanceOfRedis()
{
$factory = new RedisConnectionFactory([
'vendor' => 'custom',
'redis' => new \stdClass(),
'lazy' => false,
]);

$this->expectException(\LogicException::class);
$this->expectExceptionMessage('The redis option should be instance of "Enqueue\Redis\Redis".');
$factory->createContext();
}

public function testShouldUseCustomRedisInstance()
{
$redisMock = $this->createMock(Redis::class);

$factory = new RedisConnectionFactory([
'vendor' => 'custom',
'redis' => $redisMock,
'lazy' => false,
]);

$context = $factory->createContext();

$this->assertAttributeSame($redisMock, 'redis', $context);
}
}
29 changes: 29 additions & 0 deletions pkg/redis/Tests/Symfony/RedisTransportFactoryTest.php
Original file line number Diff line number Diff line change
@@ -104,6 +104,35 @@ public function testShouldCreateConnectionFactory()
]], $factory->getArguments());
}

public function testShouldCreateConnectionFactoryWithCustomRedisInstance()
{
$container = new ContainerBuilder();

$transport = new RedisTransportFactory();

$serviceId = $transport->createConnectionFactory($container, [
'host' => 'localhost',
'port' => 123,
'vendor' => 'custom',
'redis' => 'a.redis.service',
]);

$this->assertTrue($container->hasDefinition($serviceId));
$factory = $container->getDefinition($serviceId);
$this->assertEquals(RedisConnectionFactory::class, $factory->getClass());

$config = $factory->getArgument(0);

$this->assertInternalType('array', $config);

$this->assertArrayHasKey('vendor', $config);
$this->assertSame('custom', $config['vendor']);

$this->assertArrayHasKey('redis', $config);
$this->assertInstanceOf(Reference::class, $config['redis']);
$this->assertSame('a.redis.service', (string) $config['redis']);
}

public function testShouldCreateContext()
{
$container = new ContainerBuilder();
24 changes: 16 additions & 8 deletions pkg/simple-client/SimpleClient.php
Original file line number Diff line number Diff line change
@@ -26,14 +26,20 @@
use Interop\Queue\PsrContext;
use Interop\Queue\PsrProcessor;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;

final class SimpleClient
{
/**
* @var ContainerBuilder
* @var ContainerInterface
*/
private $container;

/**
* @var array|string
*/
private $config;

/**
* The config could be a transport DSN (string) or an array, here's an example of a few DSNs:.
*
@@ -73,11 +79,13 @@ final class SimpleClient
* ]
*
*
* @param string|array $config
* @param string|array $config
* @param ContainerBuilder|null $container
*/
public function __construct($config)
public function __construct($config, ContainerBuilder $container = null)
{
$this->container = $this->buildContainer($config);
$this->container = $this->buildContainer($config, $container ?: new ContainerBuilder());
$this->config = $config;
}

/**
@@ -252,16 +260,16 @@ public function getRouterProcessor()
}

/**
* @param array|string $config
* @param array|string $config
* @param ContainerBuilder $container
*
* @return ContainerBuilder
* @return ContainerInterface
*/
private function buildContainer($config)
private function buildContainer($config, ContainerBuilder $container)
{
$config = $this->buildConfig($config);
$extension = $this->buildContainerExtension();

$container = new ContainerBuilder();
$container->registerExtension($extension);
$container->loadFromExtension($extension->getAlias(), $config);