From 6a80a7c109cf1e279de3813a4d7500b376e54466 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 13 Oct 2017 14:39:18 +0300 Subject: [PATCH 1/6] [BC break][amqp] Introduce connection config. Make it same accross all transports. --- pkg/amqp-bunny/AmqpConnectionFactory.php | 171 +++------ .../Tests/AmqpConnectionFactoryConfigTest.php | 252 ------------ .../Tests/AmqpConnectionFactoryTest.php | 28 ++ pkg/amqp-ext/AmqpConnectionFactory.php | 176 ++------- .../Tests/AmqpConnectionFactoryConfigTest.php | 285 -------------- .../Tests/AmqpConnectionFactoryTest.php | 10 + pkg/amqp-lib/AmqpConnectionFactory.php | 263 ++++--------- .../Tests/AmqpConnectionFactoryConfigTest.php | 362 ------------------ .../Tests/AmqpConnectionFactoryTest.php | 28 ++ pkg/amqp-tools/ConnectionConfig.php | 331 ++++++++++++++++ pkg/amqp-tools/Tests/ConnectionConfigTest.php | 343 +++++++++++++++++ 11 files changed, 913 insertions(+), 1336 deletions(-) delete mode 100644 pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php create mode 100644 pkg/amqp-bunny/Tests/AmqpConnectionFactoryTest.php delete mode 100644 pkg/amqp-ext/Tests/AmqpConnectionFactoryConfigTest.php delete mode 100644 pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php create mode 100644 pkg/amqp-lib/Tests/AmqpConnectionFactoryTest.php create mode 100644 pkg/amqp-tools/ConnectionConfig.php create mode 100644 pkg/amqp-tools/Tests/ConnectionConfigTest.php diff --git a/pkg/amqp-bunny/AmqpConnectionFactory.php b/pkg/amqp-bunny/AmqpConnectionFactory.php index ab1fb09bf..78f5a5d37 100644 --- a/pkg/amqp-bunny/AmqpConnectionFactory.php +++ b/pkg/amqp-bunny/AmqpConnectionFactory.php @@ -3,6 +3,7 @@ namespace Enqueue\AmqpBunny; use Bunny\Client; +use Enqueue\AmqpTools\ConnectionConfig; use Enqueue\AmqpTools\DelayStrategyAware; use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory; @@ -12,7 +13,7 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate use DelayStrategyAwareTrait; /** - * @var array + * @var ConnectionConfig */ private $config; @@ -22,65 +23,27 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate private $client; /** - * The config could be an array, string DSN or null. In case of null it will attempt to connect to localhost with default credentials. + * @see \Enqueue\AmqpTools\ConnectionConfig for possible config formats and values * - * [ - * 'host' => 'amqp.host The host to connect too. Note: Max 1024 characters.', - * 'port' => 'amqp.port Port on the host.', - * 'vhost' => 'amqp.vhost The virtual host on the host. Note: Max 128 characters.', - * 'user' => 'amqp.user The user name to use. Note: Max 128 characters.', - * 'pass' => 'amqp.password Password. Note: Max 128 characters.', - * 'lazy' => 'the connection will be performed as later as possible, if the option set to true', - * 'receive_method' => 'Could be either basic_get or basic_consume', - * 'qos_prefetch_size' => 'The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit"', - * 'qos_prefetch_count' => 'Specifies a prefetch window in terms of whole messages.', - * 'qos_global' => 'If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection.', - * ] + * In addition this factory accepts next options: + * receive_method - Could be either basic_get or basic_consume * - * or - * - * amqp://user:pass@host:10000/vhost?lazy=true&socket=true - * - * @param array|string $config + * @param array|string|null $config */ public function __construct($config = 'amqp:') { - if (is_string($config) && 0 === strpos($config, 'amqp+bunny:')) { - $config = str_replace('amqp+bunny:', 'amqp:', $config); - } - - if (empty($config) || 'amqp:' === $config) { - $config = []; - } elseif (is_string($config)) { - $config = $this->parseDsn($config); - } elseif (is_array($config)) { - } else { - throw new \LogicException('The config must be either an array of options, a DSN string or null'); - } - - $config = array_replace($this->defaultConfig(), $config); - - $config = array_replace($this->defaultConfig(), $config); - if (array_key_exists('qos_global', $config)) { - $config['qos_global'] = (bool) $config['qos_global']; - } - if (array_key_exists('qos_prefetch_count', $config)) { - $config['qos_prefetch_count'] = (int) $config['qos_prefetch_count']; - } - if (array_key_exists('qos_prefetch_size', $config)) { - $config['qos_prefetch_size'] = (int) $config['qos_prefetch_size']; - } - if (array_key_exists('lazy', $config)) { - $config['lazy'] = (bool) $config['lazy']; - } - - $this->config = $config; + $this->config = (new ConnectionConfig($config)) + ->addSupportedSchemes('amqp+bunny') + ->addDefaultOption('receive_method', 'basic_get') + ->addDefaultOption('tcp_nodelay', null) + ->parse() + ; $supportedMethods = ['basic_get', 'basic_consume']; - if (false == in_array($this->config['receive_method'], $supportedMethods, true)) { + if (false == in_array($this->config->getOption('receive_method'), $supportedMethods, true)) { throw new \LogicException(sprintf( 'Invalid "receive_method" option value "%s". It could be only "%s"', - $this->config['receive_method'], + $this->config->getOption('receive_method'), implode('", "', $supportedMethods) )); } @@ -91,99 +54,65 @@ public function __construct($config = 'amqp:') */ public function createContext() { - if ($this->config['lazy']) { + if ($this->config->isLazy()) { $context = new AmqpContext(function () { $channel = $this->establishConnection()->channel(); - $channel->qos($this->config['qos_prefetch_size'], $this->config['qos_prefetch_count'], $this->config['qos_global']); + $channel->qos($this->config->getQosPrefetchSize(), $this->config->getQosPrefetchCount(), $this->config->isQosGlobal()); return $channel; - }, $this->config); + }, $this->config->getConfig()); $context->setDelayStrategy($this->delayStrategy); return $context; } - $context = new AmqpContext($this->establishConnection()->channel(), $this->config); + $context = new AmqpContext($this->establishConnection()->channel(), $this->config->getConfig()); $context->setDelayStrategy($this->delayStrategy); - $context->setQos($this->config['qos_prefetch_size'], $this->config['qos_prefetch_count'], $this->config['qos_global']); + $context->setQos($this->config->getQosPrefetchSize(), $this->config->getQosPrefetchCount(), $this->config->isQosGlobal()); return $context; } /** - * @return Client + * @return ConnectionConfig */ - private function establishConnection() + public function getConfig() { - if (false == $this->client) { - $this->client = new Client($this->config); - $this->client->connect(); - } - - return $this->client; + return $this->config; } /** - * @param string $dsn - * - * @return array + * @return Client */ - private function parseDsn($dsn) + private function establishConnection() { - $dsnConfig = parse_url($dsn); - if (false === $dsnConfig) { - throw new \LogicException(sprintf('Failed to parse DSN "%s"', $dsn)); - } - - $dsnConfig = array_replace([ - 'scheme' => null, - 'host' => null, - 'port' => null, - 'user' => null, - 'pass' => null, - 'path' => null, - 'query' => null, - ], $dsnConfig); - - if ('amqp' !== $dsnConfig['scheme']) { - throw new \LogicException(sprintf('The given DSN scheme "%s" is not supported. Could be "amqp" only.', $dsnConfig['scheme'])); - } - - if ($dsnConfig['query']) { - $query = []; - parse_str($dsnConfig['query'], $query); - - $dsnConfig = array_replace($query, $dsnConfig); + if (false == $this->client) { + $bunnyConfig = []; + $bunnyConfig['host'] = $this->config->getHost(); + $bunnyConfig['port'] = $this->config->getPort(); + $bunnyConfig['vhost'] = $this->config->getVHost(); + $bunnyConfig['user'] = $this->config->getUser(); + $bunnyConfig['password'] = $this->config->getPass(); + $bunnyConfig['read_write_timeout'] = min($this->config->getReadTimeout(), $this->config->getWriteTimeout()); + $bunnyConfig['timeout'] = $this->config->getConnectionTimeout(); + +// $bunnyConfig['persistent'] = $this->config->isPersisted(); +// if ($this->config->isPersisted()) { +// $bunnyConfig['path'] = $this->config->getOption('path', $this->config->getOption('vhost')); +// } + + if ($this->config->getHeartbeat()) { + $bunnyConfig['heartbeat'] = $this->config->getHeartbeat(); + } + + if (null !== $this->config->getOption('tcp_nodelay')) { + $bunnyConfig['tcp_nodelay'] = $this->config->getOption('tcp_nodelay'); + } + + $this->client = new Client($bunnyConfig); + $this->client->connect(); } - $dsnConfig['vhost'] = ltrim($dsnConfig['path'], '/'); - - unset($dsnConfig['scheme'], $dsnConfig['query'], $dsnConfig['fragment'], $dsnConfig['path']); - - $dsnConfig = array_map(function ($value) { - return urldecode($value); - }, $dsnConfig); - - return $dsnConfig; - } - - /** - * @return array - */ - private function defaultConfig() - { - return [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'lazy' => true, - 'vhost' => '/', - 'heartbeat' => 0, - 'receive_method' => 'basic_get', - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ]; + return $this->client; } } diff --git a/pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php b/pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php deleted file mode 100644 index 376ca33c4..000000000 --- a/pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php +++ /dev/null @@ -1,252 +0,0 @@ -expectException(\LogicException::class); - $this->expectExceptionMessage('The config must be either an array of options, a DSN string or null'); - - new AmqpConnectionFactory(new \stdClass()); - } - - public function testThrowIfSchemeIsNotAmqp() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('The given DSN scheme "http" is not supported. Could be "amqp" only.'); - - new AmqpConnectionFactory('http://example.com'); - } - - public function testThrowIfDsnCouldNotBeParsed() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Failed to parse DSN "amqp://:@/"'); - - new AmqpConnectionFactory('amqp://:@/'); - } - - public function testThrowIfReceiveMenthodIsInvalid() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Invalid "receive_method" option value "invalidMethod". It could be only "basic_get", "basic_consume"'); - - new AmqpConnectionFactory(['receive_method' => 'invalidMethod']); - } - - /** - * @dataProvider provideConfigs - * - * @param mixed $config - * @param mixed $expectedConfig - */ - public function testShouldParseConfigurationAsExpected($config, $expectedConfig) - { - $factory = new AmqpConnectionFactory($config); - - $this->assertAttributeEquals($expectedConfig, 'config', $factory); - } - - public static function provideConfigs() - { - yield [ - null, - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - // some examples from Appendix A: Examples (https://www.rabbitmq.com/uri-spec.html) - - yield [ - 'amqp+bunny:', - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - yield [ - 'amqp+bunny://user:pass@host:10000/vhost', - [ - 'host' => 'host', - 'port' => '10000', - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost', - [ - 'host' => 'host', - 'port' => '10000', - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - yield [ - 'amqp://user%61:%61pass@ho%61st:10000/v%2fhost', - [ - 'host' => 'hoast', - 'port' => '10000', - 'vhost' => 'v/host', - 'user' => 'usera', - 'pass' => 'apass', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - yield [ - 'amqp:', - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost?qos_prefetch_count=2&qos_prefetch_size=1', - [ - 'host' => 'host', - 'port' => '10000', - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => '1', - 'qos_prefetch_count' => '2', - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - yield [ - [], - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - yield [ - ['qos_global' => true, 'host' => 'host'], - [ - 'host' => 'host', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => true, - 'lazy' => true, - ], - ]; - - yield [ - ['qos_prefetch_count' => 123, 'qos_prefetch_size' => 321], - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 321, - 'qos_prefetch_count' => 123, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost?qos_prefetch_size=123&qos_prefetch_count=321', - [ - 'host' => 'host', - 'port' => '10000', - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - 'qos_prefetch_size' => 123, - 'qos_prefetch_count' => 321, - 'qos_global' => false, - 'lazy' => true, - ], - ]; - } -} diff --git a/pkg/amqp-bunny/Tests/AmqpConnectionFactoryTest.php b/pkg/amqp-bunny/Tests/AmqpConnectionFactoryTest.php new file mode 100644 index 000000000..c4e6a1e64 --- /dev/null +++ b/pkg/amqp-bunny/Tests/AmqpConnectionFactoryTest.php @@ -0,0 +1,28 @@ +assertClassImplements(PsrConnectionFactory::class, AmqpConnectionFactory::class); + } + + public function testShouldSupportAmqpLibScheme() + { + // no exception here + new AmqpConnectionFactory('amqp+bunny:'); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The given DSN scheme "amqp+foo" is not supported. Could be one of "amqp", "amqp+bunny" only.'); + new AmqpConnectionFactory('amqp+foo:'); + } +} diff --git a/pkg/amqp-ext/AmqpConnectionFactory.php b/pkg/amqp-ext/AmqpConnectionFactory.php index 85adb0d05..ee7e8cad8 100644 --- a/pkg/amqp-ext/AmqpConnectionFactory.php +++ b/pkg/amqp-ext/AmqpConnectionFactory.php @@ -2,6 +2,7 @@ namespace Enqueue\AmqpExt; +use Enqueue\AmqpTools\ConnectionConfig; use Enqueue\AmqpTools\DelayStrategyAware; use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory; @@ -11,7 +12,7 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate use DelayStrategyAwareTrait; /** - * @var array + * @var ConnectionConfig */ private $config; @@ -21,58 +22,31 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate private $connection; /** - * The config could be an array, string DSN or null. In case of null it will attempt to connect to localhost with default credentials. + * @see \Enqueue\AmqpTools\ConnectionConfig for possible config formats and values * - * [ - * 'host' => 'amqp.host The host to connect too. Note: Max 1024 characters.', - * 'port' => 'amqp.port Port on the host.', - * 'vhost' => 'amqp.vhost The virtual host on the host. Note: Max 128 characters.', - * 'user' => 'amqp.user The user name to use. Note: Max 128 characters.', - * 'pass' => 'amqp.password Password. Note: Max 128 characters.', - * 'read_timeout' => 'Timeout in for income activity. Note: 0 or greater seconds. May be fractional.', - * 'write_timeout' => 'Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional.', - * 'connect_timeout' => 'Connection timeout. Note: 0 or greater seconds. May be fractional.', - * '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', - * 'qos_prefetch_size' => 'The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit"', - * 'qos_prefetch_count' => 'Specifies a prefetch window in terms of whole messages.', - * 'qos_global' => 'If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection.', - * 'receive_method' => 'Could be either basic_get or basic_consume', - * ] + * In addition this factory accepts next options: + * receive_method - Could be either basic_get or basic_consume * - * or - * - * amqp://user:pass@host:10000/vhost?lazy=true&persisted=false&read_timeout=2 - * - * @param array|string $config + * @param array|string|null $config */ public function __construct($config = 'amqp:') { - if (is_string($config) && 0 === strpos($config, 'amqp+ext:')) { - $config = str_replace('amqp+ext:', 'amqp:', $config); - } - - if (empty($config) || 'amqp:' === $config) { - $config = []; - } elseif (is_string($config)) { - $config = $this->parseDsn($config); - } elseif (is_array($config)) { - } else { - throw new \LogicException('The config must be either an array of options, a DSN string or null'); - } - - $this->config = array_replace($this->defaultConfig(), $config); + $this->config = (new ConnectionConfig($config)) + ->addSupportedSchemes('amqp+ext') + ->addDefaultOption('receive_method', 'basic_get') + ->parse() + ; $supportedMethods = ['basic_get', 'basic_consume']; - if (false == in_array($this->config['receive_method'], $supportedMethods, true)) { + if (false == in_array($this->config->getOption('receive_method'), $supportedMethods, true)) { throw new \LogicException(sprintf( 'Invalid "receive_method" option value "%s". It could be only "%s"', - $this->config['receive_method'], + $this->config->getOption('receive_method'), implode('", "', $supportedMethods) )); } - if ('basic_consume' == $this->config['receive_method']) { + if ('basic_consume' == $this->config->getOption('receive_method')) { if (false == (version_compare(phpversion('amqp'), '1.9.1', '>=') || '1.9.1-dev' == phpversion('amqp'))) { // @see https://github.com/php-enqueue/enqueue-dev/issues/110 and https://github.com/pdezwart/php-amqp/issues/281 throw new \LogicException('The "basic_consume" method does not work on amqp extension prior 1.9.1 version.'); @@ -87,13 +61,13 @@ public function __construct($config = 'amqp:') */ public function createContext() { - if ($this->config['lazy']) { + if ($this->config->isLazy()) { $context = new AmqpContext(function () { $extContext = $this->createExtContext($this->establishConnection()); - $extContext->qos($this->config['qos_prefetch_size'], $this->config['qos_prefetch_count']); + $extContext->qos($this->config->getQosPrefetchSize(), $this->config->getQosPrefetchCount()); return $extContext; - }, $this->config['receive_method']); + }, $this->config->getOption('receive_method')); $context->setDelayStrategy($this->delayStrategy); return $context; @@ -101,11 +75,19 @@ public function createContext() $context = new AmqpContext($this->createExtContext($this->establishConnection()), $this->config['receive_method']); $context->setDelayStrategy($this->delayStrategy); - $context->setQos($this->config['qos_prefetch_size'], $this->config['qos_prefetch_count'], $this->config['qos_global']); + $context->setQos($this->config->getQosPrefetchSize(), $this->config->getQosPrefetchCount(), $this->config->isQosGlobal()); return $context; } + /** + * @return ConnectionConfig + */ + public function getConfig() + { + return $this->config; + } + /** * @param \AMQPConnection $extConnection * @@ -122,102 +104,24 @@ private function createExtContext(\AMQPConnection $extConnection) private function establishConnection() { if (false == $this->connection) { - $config = $this->config; - $config['login'] = $this->config['user']; - $config['password'] = $this->config['pass']; - - $this->connection = new \AMQPConnection($config); - - $this->config['persisted'] ? $this->connection->pconnect() : $this->connection->connect(); + $extConfig = []; + $extConfig['host'] = $this->config->getHost(); + $extConfig['port'] = $this->config->getPort(); + $extConfig['vhost'] = $this->config->getVHost(); + $extConfig['login'] = $this->config->getUser(); + $extConfig['password'] = $this->config->getPass(); + $extConfig['read_timeout'] = $this->config->getReadTimeout(); + $extConfig['write_timeout'] = $this->config->getWriteTimeout(); + $extConfig['connect_timeout'] = $this->config->getConnectionTimeout(); + + $this->connection = new \AMQPConnection($extConfig); + + $this->config->isPersisted() ? $this->connection->pconnect() : $this->connection->connect(); } if (false == $this->connection->isConnected()) { - $this->config['persisted'] ? $this->connection->preconnect() : $this->connection->reconnect(); + $this->config->isPersisted() ? $this->connection->preconnect() : $this->connection->reconnect(); } return $this->connection; } - - /** - * @param string $dsn - * - * @return array - */ - private function parseDsn($dsn) - { - $dsnConfig = parse_url($dsn); - if (false === $dsnConfig) { - throw new \LogicException(sprintf('Failed to parse DSN "%s"', $dsn)); - } - - $dsnConfig = array_replace([ - 'scheme' => null, - 'host' => null, - 'port' => null, - 'user' => null, - 'pass' => null, - 'path' => null, - 'query' => null, - ], $dsnConfig); - - if ('amqp' !== $dsnConfig['scheme']) { - throw new \LogicException(sprintf('The given DSN scheme "%s" is not supported. Could be "amqp" only.', $dsnConfig['scheme'])); - } - - if ($dsnConfig['query']) { - $query = []; - parse_str($dsnConfig['query'], $query); - - $dsnConfig = array_replace($query, $dsnConfig); - } - - $dsnConfig['vhost'] = ltrim($dsnConfig['path'], '/'); - - unset($dsnConfig['scheme'], $dsnConfig['query'], $dsnConfig['fragment'], $dsnConfig['path']); - - $config = array_replace($this->defaultConfig(), $dsnConfig); - $config = array_map(function ($value) { - return urldecode($value); - }, $config); - - if (array_key_exists('qos_global', $config)) { - $config['qos_global'] = (bool) $config['qos_global']; - } - if (array_key_exists('qos_prefetch_count', $config)) { - $config['qos_prefetch_count'] = (int) $config['qos_prefetch_count']; - } - if (array_key_exists('qos_prefetch_size', $config)) { - $config['qos_prefetch_size'] = (int) $config['qos_prefetch_size']; - } - if (array_key_exists('lazy', $config)) { - $config['lazy'] = (bool) $config['lazy']; - } - if (array_key_exists('persisted', $config)) { - $config['persisted'] = (bool) $config['persisted']; - } - - return $config; - } - - /** - * @return array - */ - private function defaultConfig() - { - return [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ]; - } } diff --git a/pkg/amqp-ext/Tests/AmqpConnectionFactoryConfigTest.php b/pkg/amqp-ext/Tests/AmqpConnectionFactoryConfigTest.php deleted file mode 100644 index 9629ce455..000000000 --- a/pkg/amqp-ext/Tests/AmqpConnectionFactoryConfigTest.php +++ /dev/null @@ -1,285 +0,0 @@ -expectException(\LogicException::class); - $this->expectExceptionMessage('The config must be either an array of options, a DSN string or null'); - - new AmqpConnectionFactory(new \stdClass()); - } - - public function testThrowIfSchemeIsNotAmqp() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('The given DSN scheme "http" is not supported. Could be "amqp" only.'); - - new AmqpConnectionFactory('http://example.com'); - } - - public function testThrowIfDsnCouldNotBeParsed() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Failed to parse DSN "amqp://:@/"'); - - new AmqpConnectionFactory('amqp://:@/'); - } - - public function testThrowIfReceiveMenthodIsInvalid() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Invalid "receive_method" option value "invalidMethod". It could be only "basic_get", "basic_consume"'); - - new AmqpConnectionFactory(['receive_method' => 'invalidMethod']); - } - - /** - * @dataProvider provideConfigs - * - * @param mixed $config - * @param mixed $expectedConfig - */ - public function testShouldParseConfigurationAsExpected($config, $expectedConfig) - { - $factory = new AmqpConnectionFactory($config); - - $this->assertAttributeEquals($expectedConfig, 'config', $factory); - } - - public static function provideConfigs() - { - yield [ - null, - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - // some examples from Appendix A: Examples (https://www.rabbitmq.com/uri-spec.html) - - yield [ - 'amqp+ext:', - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - 'amqp+ext://user:pass@host:10000/vhost', - [ - 'host' => 'host', - 'port' => 10000, - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost', - [ - 'host' => 'host', - 'port' => 10000, - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - 'amqp://user%61:%61pass@ho%61st:10000/v%2fhost', - [ - 'host' => 'hoast', - 'port' => 10000, - 'vhost' => 'v/host', - 'user' => 'usera', - 'pass' => 'apass', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - 'amqp:', - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost?connect_timeout=2&lazy=', - [ - 'host' => 'host', - 'port' => 10000, - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => '2', - 'persisted' => false, - 'lazy' => '', - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - [], - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - ['lazy' => false, 'host' => 'host'], - [ - 'host' => 'host', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => false, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - ['qos_prefetch_count' => 123, 'qos_prefetch_size' => 321], - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_count' => 123, - 'qos_prefetch_size' => 321, - 'qos_global' => false, - 'receive_method' => 'basic_get', - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost?qos_prefetch_count=123&qos_prefetch_size=321&qos_global=1', - [ - 'host' => 'host', - 'port' => '10000', - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'read_timeout' => null, - 'write_timeout' => null, - 'connect_timeout' => null, - 'persisted' => false, - 'lazy' => true, - 'qos_prefetch_size' => 321, - 'qos_prefetch_count' => 123, - 'qos_global' => true, - 'receive_method' => 'basic_get', - ], - ]; - } -} diff --git a/pkg/amqp-ext/Tests/AmqpConnectionFactoryTest.php b/pkg/amqp-ext/Tests/AmqpConnectionFactoryTest.php index bc24157d0..251e57439 100644 --- a/pkg/amqp-ext/Tests/AmqpConnectionFactoryTest.php +++ b/pkg/amqp-ext/Tests/AmqpConnectionFactoryTest.php @@ -17,6 +17,16 @@ public function testShouldImplementConnectionFactoryInterface() $this->assertClassImplements(PsrConnectionFactory::class, AmqpConnectionFactory::class); } + public function testShouldSupportAmqpExtScheme() + { + // no exception here + new AmqpConnectionFactory('amqp+ext:'); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The given DSN scheme "amqp+foo" is not supported. Could be one of "amqp", "amqp+ext" only.'); + new AmqpConnectionFactory('amqp+foo:'); + } + public function testShouldCreateLazyContext() { $factory = new AmqpConnectionFactory(['lazy' => true]); diff --git a/pkg/amqp-lib/AmqpConnectionFactory.php b/pkg/amqp-lib/AmqpConnectionFactory.php index 90385e8a9..01571ae87 100644 --- a/pkg/amqp-lib/AmqpConnectionFactory.php +++ b/pkg/amqp-lib/AmqpConnectionFactory.php @@ -2,6 +2,7 @@ namespace Enqueue\AmqpLib; +use Enqueue\AmqpTools\ConnectionConfig; use Enqueue\AmqpTools\DelayStrategyAware; use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory; @@ -16,7 +17,7 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate use DelayStrategyAwareTrait; /** - * @var array + * @var ConnectionConfig */ private $config; @@ -26,64 +27,32 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate private $connection; /** - * The config could be an array, string DSN or null. In case of null it will attempt to connect to localhost with default credentials. + * @see \Enqueue\AmqpTools\ConnectionConfig for possible config formats and values * - * [ - * 'host' => 'amqp.host The host to connect too. Note: Max 1024 characters.', - * 'port' => 'amqp.port Port on the host.', - * 'vhost' => 'amqp.vhost The virtual host on the host. Note: Max 128 characters.', - * 'user' => 'amqp.user The user name to use. Note: Max 128 characters.', - * 'pass' => 'amqp.password Password. Note: Max 128 characters.', - * 'lazy' => 'the connection will be performed as later as possible, if the option set to true', - * 'stream' => 'stream or socket connection', - * 'receive_method' => 'Could be either basic_get or basic_consume', - * 'qos_prefetch_size' => 'The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit"', - * 'qos_prefetch_count' => 'Specifies a prefetch window in terms of whole messages.', - * 'qos_global' => 'If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection.', - * ] + * In addition this factory accepts next options: + * receive_method - Could be either basic_get or basic_consume * - * or - * - * amqp://user:pass@host:10000/vhost?lazy=true&socket=true - * - * @param array|string $config + * @param array|string|null $config */ public function __construct($config = 'amqp:') { - if (is_string($config) && 0 === strpos($config, 'amqp+lib:')) { - $config = str_replace('amqp+lib:', 'amqp:', $config); - } - - if (empty($config) || 'amqp:' === $config) { - $config = []; - } elseif (is_string($config)) { - $config = $this->parseDsn($config); - } elseif (is_array($config)) { - } else { - throw new \LogicException('The config must be either an array of options, a DSN string or null'); - } - - $config = array_replace($this->defaultConfig(), $config); - if (array_key_exists('qos_global', $config)) { - $config['qos_global'] = (bool) $config['qos_global']; - } - if (array_key_exists('qos_prefetch_count', $config)) { - $config['qos_prefetch_count'] = (int) $config['qos_prefetch_count']; - } - if (array_key_exists('qos_prefetch_size', $config)) { - $config['qos_prefetch_size'] = (int) $config['qos_prefetch_size']; - } - if (array_key_exists('lazy', $config)) { - $config['lazy'] = (bool) $config['lazy']; - } - - $this->config = $config; + $this->config = (new ConnectionConfig($config)) + ->addSupportedSchemes('amqp+lib') + ->addDefaultOption('stream', true) + ->addDefaultOption('insist', false) + ->addDefaultOption('login_method', 'AMQPLAIN') + ->addDefaultOption('login_response', null) + ->addDefaultOption('locale', 'en_US') + ->addDefaultOption('keepalive', false) + ->addDefaultOption('receive_method', 'basic_get') + ->parse() + ; $supportedMethods = ['basic_get', 'basic_consume']; - if (false == in_array($this->config['receive_method'], $supportedMethods, true)) { + if (false == in_array($this->config->getOption('receive_method'), $supportedMethods, true)) { throw new \LogicException(sprintf( 'Invalid "receive_method" option value "%s". It could be only "%s"', - $this->config['receive_method'], + $this->config->getOption('receive_method'), implode('", "', $supportedMethods) )); } @@ -94,86 +63,94 @@ public function __construct($config = 'amqp:') */ public function createContext() { - $context = new AmqpContext($this->establishConnection(), $this->config); + $context = new AmqpContext($this->establishConnection(), $this->config->getConfig()); $context->setDelayStrategy($this->delayStrategy); return $context; } + /** + * @return ConnectionConfig + */ + public function getConfig() + { + return $this->config; + } + /** * @return AbstractConnection */ private function establishConnection() { if (false == $this->connection) { - if ($this->config['stream']) { - if ($this->config['lazy']) { + if ($this->config->getOption('stream')) { + if ($this->config->isLazy()) { $con = new AMQPLazyConnection( - $this->config['host'], - $this->config['port'], - $this->config['user'], - $this->config['pass'], - $this->config['vhost'], - $this->config['insist'], - $this->config['login_method'], - $this->config['login_response'], - $this->config['locale'], - $this->config['connection_timeout'], - $this->config['read_write_timeout'], + $this->config->getHost(), + $this->config->getPort(), + $this->config->getUser(), + $this->config->getPass(), + $this->config->getVHost(), + $this->config->getOption('insist'), + $this->config->getOption('login_method'), + $this->config->getOption('login_response'), + $this->config->getOption('locale'), + $this->config->getConnectionTimeout(), + (int) round(min($this->config->getReadTimeout(), $this->config->getWriteTimeout())), null, - $this->config['keepalive'], - $this->config['heartbeat'] + $this->config->getOption('keepalive'), + (int) round($this->config->getHeartbeat()) ); } else { $con = new AMQPStreamConnection( - $this->config['host'], - $this->config['port'], - $this->config['user'], - $this->config['pass'], - $this->config['vhost'], - $this->config['insist'], - $this->config['login_method'], - $this->config['login_response'], - $this->config['locale'], - $this->config['connection_timeout'], - $this->config['read_write_timeout'], + $this->config->getHost(), + $this->config->getPort(), + $this->config->getUser(), + $this->config->getPass(), + $this->config->getVHost(), + $this->config->getOption('insist'), + $this->config->getOption('login_method'), + $this->config->getOption('login_response'), + $this->config->getOption('locale'), + $this->config->getConnectionTimeout(), + (int) round(min($this->config->getReadTimeout(), $this->config->getWriteTimeout())), null, - $this->config['keepalive'], - $this->config['heartbeat'] + $this->config->getOption('keepalive'), + (int) round($this->config->getHeartbeat()) ); } } else { - if ($this->config['lazy']) { + if ($this->config->isLazy()) { $con = new AMQPLazySocketConnection( - $this->config['host'], - $this->config['port'], - $this->config['user'], - $this->config['pass'], - $this->config['vhost'], - $this->config['insist'], - $this->config['login_method'], - $this->config['login_response'], - $this->config['locale'], - $this->config['read_timeout'], - $this->config['keepalive'], - $this->config['write_timeout'], - $this->config['heartbeat'] + $this->config->getHost(), + $this->config->getPort(), + $this->config->getUser(), + $this->config->getPass(), + $this->config->getVHost(), + $this->config->getOption('insist'), + $this->config->getOption('login_method'), + $this->config->getOption('login_response'), + $this->config->getOption('locale'), + (int) round($this->config->getReadTimeout()), + $this->config->getOption('keepalive'), + (int) round($this->config->getWriteTimeout()), + (int) round($this->config->getHeartbeat()) ); } else { $con = new AMQPSocketConnection( - $this->config['host'], - $this->config['port'], - $this->config['user'], - $this->config['pass'], - $this->config['vhost'], - $this->config['insist'], - $this->config['login_method'], - $this->config['login_response'], - $this->config['locale'], - $this->config['read_timeout'], - $this->config['keepalive'], - $this->config['write_timeout'], - $this->config['heartbeat'] + $this->config->getHost(), + $this->config->getPort(), + $this->config->getUser(), + $this->config->getPass(), + $this->config->getVHost(), + $this->config->getOption('insist'), + $this->config->getOption('login_method'), + $this->config->getOption('login_response'), + $this->config->getOption('locale'), + (int) round($this->config->getReadTimeout()), + $this->config->getOption('keepalive'), + (int) round($this->config->getWriteTimeout()), + (int) round($this->config->getHeartbeat()) ); } } @@ -183,78 +160,4 @@ private function establishConnection() return $this->connection; } - - /** - * @param string $dsn - * - * @return array - */ - private function parseDsn($dsn) - { - $dsnConfig = parse_url($dsn); - if (false === $dsnConfig) { - throw new \LogicException(sprintf('Failed to parse DSN "%s"', $dsn)); - } - - $dsnConfig = array_replace([ - 'scheme' => null, - 'host' => null, - 'port' => null, - 'user' => null, - 'pass' => null, - 'path' => null, - 'query' => null, - ], $dsnConfig); - - if ('amqp' !== $dsnConfig['scheme']) { - throw new \LogicException(sprintf('The given DSN scheme "%s" is not supported. Could be "amqp" only.', $dsnConfig['scheme'])); - } - - if ($dsnConfig['query']) { - $query = []; - parse_str($dsnConfig['query'], $query); - - $dsnConfig = array_replace($query, $dsnConfig); - } - - $dsnConfig['vhost'] = ltrim($dsnConfig['path'], '/'); - - unset($dsnConfig['scheme'], $dsnConfig['query'], $dsnConfig['fragment'], $dsnConfig['path']); - - $config = array_map(function ($value) { - return urldecode($value); - }, $dsnConfig); - - return $config; - } - - /** - * @return array - */ - private function defaultConfig() - { - return [ - 'stream' => true, - 'lazy' => true, - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'read_timeout' => 3, - 'keepalive' => false, - 'write_timeout' => 3, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'receive_method' => 'basic_get', - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ]; - } } diff --git a/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php b/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php deleted file mode 100644 index 48eb0d424..000000000 --- a/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php +++ /dev/null @@ -1,362 +0,0 @@ -expectException(\LogicException::class); - $this->expectExceptionMessage('The config must be either an array of options, a DSN string or null'); - - new AmqpConnectionFactory(new \stdClass()); - } - - public function testThrowIfSchemeIsNotAmqp() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('The given DSN scheme "http" is not supported. Could be "amqp" only.'); - - new AmqpConnectionFactory('http://example.com'); - } - - public function testThrowIfDsnCouldNotBeParsed() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Failed to parse DSN "amqp://:@/"'); - - new AmqpConnectionFactory('amqp://:@/'); - } - - public function testThrowIfReceiveMenthodIsInvalid() - { - $this->expectException(\LogicException::class); - $this->expectExceptionMessage('Invalid "receive_method" option value "invalidMethod". It could be only "basic_get", "basic_consume"'); - - new AmqpConnectionFactory(['receive_method' => 'invalidMethod']); - } - - /** - * @dataProvider provideConfigs - * - * @param mixed $config - * @param mixed $expectedConfig - */ - public function testShouldParseConfigurationAsExpected($config, $expectedConfig) - { - $factory = new AmqpConnectionFactory($config); - - $this->assertAttributeEquals($expectedConfig, 'config', $factory); - } - - public static function provideConfigs() - { - yield [ - null, - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - // some examples from Appendix A: Examples (https://www.rabbitmq.com/uri-spec.html) - - yield [ - 'amqp+lib:', - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - 'amqp+lib://user:pass@host:10000/vhost', - [ - 'host' => 'host', - 'port' => 10000, - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost', - [ - 'host' => 'host', - 'port' => 10000, - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - 'amqp://user%61:%61pass@ho%61st:10000/v%2fhost', - [ - 'host' => 'hoast', - 'port' => 10000, - 'vhost' => 'v/host', - 'user' => 'usera', - 'pass' => 'apass', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - 'amqp:', - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost?connection_timeout=2&lazy=', - [ - 'host' => 'host', - 'port' => 10000, - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => '', - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => '2', - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - [], - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - ['lazy' => false, 'host' => 'host'], - [ - 'host' => 'host', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => false, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - ['connection_timeout' => 123, 'read_write_timeout' => 321], - [ - 'host' => 'localhost', - 'port' => 5672, - 'vhost' => '/', - 'user' => 'guest', - 'pass' => 'guest', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => 123, - 'read_write_timeout' => 321, - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - - yield [ - 'amqp://user:pass@host:10000/vhost?connection_timeout=123&read_write_timeout=321', - [ - 'host' => 'host', - 'port' => 10000, - 'vhost' => 'vhost', - 'user' => 'user', - 'pass' => 'pass', - 'read_timeout' => 3, - 'write_timeout' => 3, - 'lazy' => true, - 'receive_method' => 'basic_get', - 'stream' => true, - 'insist' => false, - 'login_method' => 'AMQPLAIN', - 'login_response' => null, - 'locale' => 'en_US', - 'keepalive' => false, - 'heartbeat' => 0, - 'connection_timeout' => '123', - 'read_write_timeout' => '321', - 'qos_prefetch_size' => 0, - 'qos_prefetch_count' => 1, - 'qos_global' => false, - ], - ]; - } -} diff --git a/pkg/amqp-lib/Tests/AmqpConnectionFactoryTest.php b/pkg/amqp-lib/Tests/AmqpConnectionFactoryTest.php new file mode 100644 index 000000000..4bcf8f156 --- /dev/null +++ b/pkg/amqp-lib/Tests/AmqpConnectionFactoryTest.php @@ -0,0 +1,28 @@ +assertClassImplements(PsrConnectionFactory::class, AmqpConnectionFactory::class); + } + + public function testShouldSupportAmqpLibScheme() + { + // no exception here + new AmqpConnectionFactory('amqp+lib:'); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The given DSN scheme "amqp+foo" is not supported. Could be one of "amqp", "amqp+lib" only.'); + new AmqpConnectionFactory('amqp+foo:'); + } +} diff --git a/pkg/amqp-tools/ConnectionConfig.php b/pkg/amqp-tools/ConnectionConfig.php new file mode 100644 index 000000000..99f19c3a8 --- /dev/null +++ b/pkg/amqp-tools/ConnectionConfig.php @@ -0,0 +1,331 @@ +inputConfig = $config; + + $this->supportedSchemes = []; + $this->defaultConfig = [ + 'host' => 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'vhost' => '/', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'heartbeat' => 0, + 'persisted' => true, + 'lazy' => true, + 'qos_global' => false, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + ]; + + $this->addSupportedSchemes('amqp'); + } + + /** + * @param string $schema + * + * @return self + */ + public function addSupportedSchemes($schema) + { + $this->supportedSchemes[] = $schema; + $this->supportedSchemes = array_unique($this->supportedSchemes); + + return $this; + } + + /** + * @param string $name + * @param mixed $value + * + * @return self + */ + public function addDefaultOption($name, $value) + { + $this->defaultConfig[$name] = $value; + + return $this; + } + + /** + * @return self + */ + public function parse() + { + if (empty($this->inputConfig) || in_array($this->inputConfig, $this->supportedSchemes, true)) { + $config = []; + } elseif (is_string($this->inputConfig)) { + $config = $this->parseDsn($this->inputConfig); + } elseif (is_array($this->inputConfig)) { + $config = $this->inputConfig; + if (array_key_exists('dsn', $config)) { + $dsn = $config['dsn']; + unset($config['dsn']); + + $config = array_replace($config, $this->parseDsn($dsn)); + } + } else { + throw new \LogicException('The config must be either an array of options, a DSN string or null'); + } + + $config = array_replace($this->defaultConfig, $config); + $config['host'] = (string) $config['host']; + $config['port'] = (int) ($config['port']); + $config['user'] = (string) $config['user']; + $config['pass'] = (string) $config['pass']; + $config['read_timeout'] = max((float) ($config['read_timeout']), 0); + $config['write_timeout'] = max((float) ($config['write_timeout']), 0); + $config['connection_timeout'] = max((float) ($config['connection_timeout']), 0); + $config['heartbeat'] = max((float) ($config['heartbeat']), 0); + $config['persisted'] = !empty($config['persisted']); + $config['lazy'] = !empty($config['lazy']); + $config['qos_global'] = !empty($config['qos_global']); + $config['qos_prefetch_count'] = max((int) ($config['qos_prefetch_count']), 0); + $config['qos_prefetch_size'] = max((int) ($config['qos_prefetch_size']), 0); + + $this->config = $config; + + return $this; + } + + /** + * @return string + */ + public function getHost() + { + return $this->getOption('host'); + } + + /** + * @return int + */ + public function getPort() + { + return $this->getOption('port'); + } + + /** + * @return string + */ + public function getUser() + { + return $this->getOption('user'); + } + + /** + * @return string + */ + public function getPass() + { + return $this->getOption('pass'); + } + + /** + * @return string + */ + public function getVHost() + { + return $this->getOption('vhost'); + } + + /** + * @return int + */ + public function getReadTimeout() + { + return $this->getOption('read_timeout'); + } + + /** + * @return int + */ + public function getWriteTimeout() + { + return $this->getOption('write_timeout'); + } + + /** + * @return int + */ + public function getConnectionTimeout() + { + return $this->getOption('connection_timeout'); + } + + /** + * @return int + */ + public function getHeartbeat() + { + return $this->getOption('heartbeat'); + } + + /** + * @return bool + */ + public function isPersisted() + { + return $this->getOption('persisted'); + } + + /** + * @return bool + */ + public function isLazy() + { + return $this->getOption('lazy'); + } + + /** + * @return bool + */ + public function isQosGlobal() + { + return $this->getOption('qos_global'); + } + + /** + * @return int + */ + public function getQosPrefetchSize() + { + return $this->getOption('qos_prefetch_size'); + } + + /** + * @return int + */ + public function getQosPrefetchCount() + { + return $this->getOption('qos_prefetch_count'); + } + + /** + * @param string $name + * @param mixed $default + * + * @return bool + */ + public function getOption($name, $default = null) + { + $config = $this->getConfig(); + + return array_key_exists($name, $config) ? $config[$name] : $default; + } + + /** + * @throws \LogicException if the input config has not been parsed + * + * @return array + */ + public function getConfig() + { + if (null === $this->config) { + throw new \LogicException('The config has not been parsed.'); + } + + return $this->config; + } + + /** + * @param string $dsn + * + * @return array + */ + private function parseDsn($dsn) + { + if (false === parse_url($dsn)) { + throw new \LogicException(sprintf('Failed to parse DSN "%s"', $dsn)); + } + + $config = []; + + $scheme = parse_url($dsn, PHP_URL_SCHEME); + if (false == in_array($scheme, $this->supportedSchemes, true)) { + throw new \LogicException(sprintf('The given DSN scheme "%s" is not supported. Could be one of "%s" only.', $scheme, implode('", "', $this->supportedSchemes))); + } + + if ($host = parse_url($dsn, PHP_URL_HOST)) { + $config['host'] = $host; + } + if ($port = parse_url($dsn, PHP_URL_PORT)) { + $config['port'] = $port; + } + if ($user = parse_url($dsn, PHP_URL_USER)) { + $config['user'] = $user; + } + if ($pass = parse_url($dsn, PHP_URL_PASS)) { + $config['pass'] = $pass; + } + + if ($query = parse_url($dsn, PHP_URL_QUERY)) { + $queryConfig = []; + parse_str($query, $queryConfig); + + $config = array_replace($queryConfig, $config); + } + + if ($path = parse_url($dsn, PHP_URL_PATH)) { + $config['vhost'] = ltrim($path, '/'); + } + + return array_map('urldecode', $config); + } +} diff --git a/pkg/amqp-tools/Tests/ConnectionConfigTest.php b/pkg/amqp-tools/Tests/ConnectionConfigTest.php new file mode 100644 index 000000000..70d1ea8f8 --- /dev/null +++ b/pkg/amqp-tools/Tests/ConnectionConfigTest.php @@ -0,0 +1,343 @@ +expectException(\LogicException::class); + $this->expectExceptionMessage('The config must be either an array of options, a DSN string or null'); + + (new ConnectionConfig(new \stdClass()))->parse(); + } + + public function testThrowIfSchemeIsNotSupported() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The given DSN scheme "http" is not supported. Could be one of "amqp" only.'); + + (new ConnectionConfig('http://example.com'))->parse(); + } + + public function testThrowIfSchemeIsNotSupportedIncludingAdditionalSupportedSchemes() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('The given DSN scheme "http" is not supported. Could be one of "amqp", "amqp+foo" only.'); + + (new ConnectionConfig('http://example.com')) + ->addSupportedSchemes('amqp+foo') + ->parse() + ; + } + + public function testThrowIfDsnCouldNotBeParsed() + { + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Failed to parse DSN "amqp://:@/"'); + + (new ConnectionConfig('amqp://:@/'))->parse(); + } + + public function testShouldParseEmptyDsnWithDriverSet() + { + $config = (new ConnectionConfig('amqp+foo:')) + ->addSupportedSchemes('amqp+foo') + ->parse() + ; + + $this->assertEquals([ + 'host' => 'localhost', + 'port' => 5672, + 'vhost' => '/', + 'user' => 'guest', + 'pass' => 'guest', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], $config->getConfig()); + } + + public function testShouldParseCustomDsnWithDriverSet() + { + $config = (new ConnectionConfig('amqp+foo://user:pass@host:10000/vhost')) + ->addSupportedSchemes('amqp+foo') + ->parse() + ; + + $this->assertEquals([ + 'host' => 'host', + 'port' => 10000, + 'vhost' => 'vhost', + 'user' => 'user', + 'pass' => 'pass', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], $config->getConfig()); + } + + /** + * @dataProvider provideConfigs + * + * @param mixed $config + * @param mixed $expectedConfig + */ + public function testShouldParseConfigurationAsExpected($config, $expectedConfig) + { + $config = new ConnectionConfig($config); + $config->parse(); + + $this->assertEquals($expectedConfig, $config->getConfig()); + } + + public static function provideConfigs() + { + yield [ + null, + [ + 'host' => 'localhost', + 'port' => 5672, + 'vhost' => '/', + 'user' => 'guest', + 'pass' => 'guest', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + 'amqp:', + [ + 'host' => 'localhost', + 'port' => 5672, + 'vhost' => '/', + 'user' => 'guest', + 'pass' => 'guest', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + 'amqp://user:pass@host:10000/vhost', + [ + 'host' => 'host', + 'port' => 10000, + 'vhost' => 'vhost', + 'user' => 'user', + 'pass' => 'pass', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + 'amqp://user%61:%61pass@ho%61st:10000/v%2fhost', + [ + 'host' => 'hoast', + 'port' => 10000, + 'vhost' => 'v/host', + 'user' => 'usera', + 'pass' => 'apass', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + 'amqp://user:pass@host:10000/vhost?connection_timeout=20&write_timeout=4&read_timeout=-4&heartbeat=23.3', + [ + 'host' => 'host', + 'port' => 10000, + 'vhost' => 'vhost', + 'user' => 'user', + 'pass' => 'pass', + 'read_timeout' => 0., + 'write_timeout' => 4, + 'connection_timeout' => 20., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + 'heartbeat' => 23.3, + ], + ]; + + yield [ + 'amqp://user:pass@host:10000/vhost?persisted=0&lazy=&qos_global=true', + [ + 'host' => 'host', + 'port' => 10000, + 'vhost' => 'vhost', + 'user' => 'user', + 'pass' => 'pass', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => false, + 'lazy' => false, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => true, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + [], + [ + 'host' => 'localhost', + 'port' => 5672, + 'vhost' => '/', + 'user' => 'guest', + 'pass' => 'guest', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + ['lazy' => false, 'persisted' => 0, 'qos_global' => 1], + [ + 'host' => 'localhost', + 'port' => 5672, + 'vhost' => '/', + 'user' => 'guest', + 'pass' => 'guest', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => false, + 'lazy' => false, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => true, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + ['qos_prefetch_count' => 123, 'qos_prefetch_size' => -2], + [ + 'host' => 'localhost', + 'port' => 5672, + 'vhost' => '/', + 'user' => 'guest', + 'pass' => 'guest', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_count' => 123, + 'qos_prefetch_size' => 0, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + 'amqp://user:pass@host:10000/vhost?qos_prefetch_count=123&qos_prefetch_size=-2', + [ + 'host' => 'host', + 'port' => 10000, + 'vhost' => 'vhost', + 'user' => 'user', + 'pass' => 'pass', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_count' => 123, + 'qos_prefetch_size' => 0, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], + ]; + + yield [ + [ + 'read_timeout' => 20., + 'write_timeout' => 30., + 'connection_timeout' => 40., + 'qos_prefetch_count' => 10, + 'dsn' => 'amqp://user:pass@host:10000/vhost?qos_prefetch_count=20', + ], + [ + 'host' => 'host', + 'port' => 10000, + 'vhost' => 'vhost', + 'user' => 'user', + 'pass' => 'pass', + 'read_timeout' => 20., + 'write_timeout' => 30., + 'connection_timeout' => 40., + 'persisted' => true, + 'lazy' => true, + 'qos_prefetch_count' => 20, + 'qos_prefetch_size' => 0, + 'qos_global' => false, + 'heartbeat' => 0.0, + ], + ]; + } +} From f7f6cc0b25d37683c9e0e2ee5db1015021dab912 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 13 Oct 2017 14:42:25 +0300 Subject: [PATCH 2/6] [amqp] ConnectionConfig::addSupportedSchemes -> addSupportedScheme --- pkg/amqp-bunny/AmqpConnectionFactory.php | 2 +- pkg/amqp-ext/AmqpConnectionFactory.php | 2 +- pkg/amqp-lib/AmqpConnectionFactory.php | 2 +- pkg/amqp-tools/ConnectionConfig.php | 4 ++-- pkg/amqp-tools/Tests/ConnectionConfigTest.php | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/amqp-bunny/AmqpConnectionFactory.php b/pkg/amqp-bunny/AmqpConnectionFactory.php index 78f5a5d37..267f35744 100644 --- a/pkg/amqp-bunny/AmqpConnectionFactory.php +++ b/pkg/amqp-bunny/AmqpConnectionFactory.php @@ -33,7 +33,7 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate public function __construct($config = 'amqp:') { $this->config = (new ConnectionConfig($config)) - ->addSupportedSchemes('amqp+bunny') + ->addSupportedScheme('amqp+bunny') ->addDefaultOption('receive_method', 'basic_get') ->addDefaultOption('tcp_nodelay', null) ->parse() diff --git a/pkg/amqp-ext/AmqpConnectionFactory.php b/pkg/amqp-ext/AmqpConnectionFactory.php index ee7e8cad8..8a7c02add 100644 --- a/pkg/amqp-ext/AmqpConnectionFactory.php +++ b/pkg/amqp-ext/AmqpConnectionFactory.php @@ -32,7 +32,7 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate public function __construct($config = 'amqp:') { $this->config = (new ConnectionConfig($config)) - ->addSupportedSchemes('amqp+ext') + ->addSupportedScheme('amqp+ext') ->addDefaultOption('receive_method', 'basic_get') ->parse() ; diff --git a/pkg/amqp-lib/AmqpConnectionFactory.php b/pkg/amqp-lib/AmqpConnectionFactory.php index 01571ae87..a44f67146 100644 --- a/pkg/amqp-lib/AmqpConnectionFactory.php +++ b/pkg/amqp-lib/AmqpConnectionFactory.php @@ -37,7 +37,7 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate public function __construct($config = 'amqp:') { $this->config = (new ConnectionConfig($config)) - ->addSupportedSchemes('amqp+lib') + ->addSupportedScheme('amqp+lib') ->addDefaultOption('stream', true) ->addDefaultOption('insist', false) ->addDefaultOption('login_method', 'AMQPLAIN') diff --git a/pkg/amqp-tools/ConnectionConfig.php b/pkg/amqp-tools/ConnectionConfig.php index 99f19c3a8..d3a9bfff7 100644 --- a/pkg/amqp-tools/ConnectionConfig.php +++ b/pkg/amqp-tools/ConnectionConfig.php @@ -75,7 +75,7 @@ public function __construct($config = null) 'qos_prefetch_count' => 1, ]; - $this->addSupportedSchemes('amqp'); + $this->addSupportedScheme('amqp'); } /** @@ -83,7 +83,7 @@ public function __construct($config = null) * * @return self */ - public function addSupportedSchemes($schema) + public function addSupportedScheme($schema) { $this->supportedSchemes[] = $schema; $this->supportedSchemes = array_unique($this->supportedSchemes); diff --git a/pkg/amqp-tools/Tests/ConnectionConfigTest.php b/pkg/amqp-tools/Tests/ConnectionConfigTest.php index 70d1ea8f8..be0094767 100644 --- a/pkg/amqp-tools/Tests/ConnectionConfigTest.php +++ b/pkg/amqp-tools/Tests/ConnectionConfigTest.php @@ -35,7 +35,7 @@ public function testThrowIfSchemeIsNotSupportedIncludingAdditionalSupportedSchem $this->expectExceptionMessage('The given DSN scheme "http" is not supported. Could be one of "amqp", "amqp+foo" only.'); (new ConnectionConfig('http://example.com')) - ->addSupportedSchemes('amqp+foo') + ->addSupportedScheme('amqp+foo') ->parse() ; } @@ -51,7 +51,7 @@ public function testThrowIfDsnCouldNotBeParsed() public function testShouldParseEmptyDsnWithDriverSet() { $config = (new ConnectionConfig('amqp+foo:')) - ->addSupportedSchemes('amqp+foo') + ->addSupportedScheme('amqp+foo') ->parse() ; @@ -76,7 +76,7 @@ public function testShouldParseEmptyDsnWithDriverSet() public function testShouldParseCustomDsnWithDriverSet() { $config = (new ConnectionConfig('amqp+foo://user:pass@host:10000/vhost')) - ->addSupportedSchemes('amqp+foo') + ->addSupportedScheme('amqp+foo') ->parse() ; From f1ff3873bb283b1c4ab46990001eab7d29d8955b Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Sat, 14 Oct 2017 00:03:34 +0300 Subject: [PATCH 3/6] Introduce generic amqp\rabbitmq transport factories. --- pkg/amqp-bunny/AmqpConnectionFactory.php | 10 +- pkg/amqp-bunny/BunnyClient.php | 18 ++ .../Symfony/AmqpBunnyTransportFactory.php | 140 ---------- .../RabbitMqAmqpBunnyTransportFactory.php | 68 ----- .../Symfony/AmqpBunnyTransportFactoryTest.php | 218 ---------------- .../RabbitMqAmqpBunnyTransportFactoryTest.php | 137 ---------- pkg/amqp-ext/AmqpConnectionFactory.php | 2 +- pkg/amqp-ext/Symfony/AmqpTransportFactory.php | 152 ----------- pkg/amqp-ext/composer.json | 2 +- .../RabbitMqAmqpLibTransportFactory.php | 68 ----- .../Symfony/AmqpLibTransportFactoryTest.php | 239 ------------------ .../RabbitMqAmqpLibTransportFactoryTest.php | 144 ----------- pkg/amqp-tools/ConnectionConfig.php | 4 +- pkg/amqp-tools/Tests/ConnectionConfigTest.php | 30 +-- pkg/enqueue-bundle/EnqueueBundle.php | 52 ++-- .../Tests/Functional/UseCasesTest.php | 10 +- .../Tests/Unit/EnqueueBundleTest.php | 39 ++- .../Symfony/AmqpTransportFactory.php} | 94 +++---- .../Symfony/DefaultTransportFactory.php | 19 +- .../Symfony/RabbitMqAmqpTransportFactory.php | 7 +- .../Symfony/AmqpTransportFactoryTest.php | 172 +++++++++---- .../Symfony/DefaultTransportFactoryTest.php | 6 +- .../RabbitMqAmqpTransportFactoryTest.php | 40 +-- 23 files changed, 304 insertions(+), 1367 deletions(-) create mode 100644 pkg/amqp-bunny/BunnyClient.php delete mode 100644 pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php delete mode 100644 pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php delete mode 100644 pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php delete mode 100644 pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php delete mode 100644 pkg/amqp-ext/Symfony/AmqpTransportFactory.php delete mode 100644 pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php delete mode 100644 pkg/amqp-lib/Tests/Symfony/AmqpLibTransportFactoryTest.php delete mode 100644 pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php rename pkg/{amqp-lib/Symfony/AmqpLibTransportFactory.php => enqueue/Symfony/AmqpTransportFactory.php} (64%) rename pkg/{amqp-ext => enqueue}/Symfony/RabbitMqAmqpTransportFactory.php (89%) rename pkg/{amqp-ext => enqueue}/Tests/Symfony/AmqpTransportFactoryTest.php (59%) rename pkg/{amqp-ext => enqueue}/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php (77%) diff --git a/pkg/amqp-bunny/AmqpConnectionFactory.php b/pkg/amqp-bunny/AmqpConnectionFactory.php index 267f35744..470819778 100644 --- a/pkg/amqp-bunny/AmqpConnectionFactory.php +++ b/pkg/amqp-bunny/AmqpConnectionFactory.php @@ -2,7 +2,6 @@ namespace Enqueue\AmqpBunny; -use Bunny\Client; use Enqueue\AmqpTools\ConnectionConfig; use Enqueue\AmqpTools\DelayStrategyAware; use Enqueue\AmqpTools\DelayStrategyAwareTrait; @@ -18,7 +17,7 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrate private $config; /** - * @var Client + * @var BunnyClient */ private $client; @@ -82,7 +81,7 @@ public function getConfig() } /** - * @return Client + * @return BunnyClient */ private function establishConnection() { @@ -96,9 +95,10 @@ private function establishConnection() $bunnyConfig['read_write_timeout'] = min($this->config->getReadTimeout(), $this->config->getWriteTimeout()); $bunnyConfig['timeout'] = $this->config->getConnectionTimeout(); + // @see https://github.com/php-enqueue/enqueue-dev/issues/229 // $bunnyConfig['persistent'] = $this->config->isPersisted(); // if ($this->config->isPersisted()) { -// $bunnyConfig['path'] = $this->config->getOption('path', $this->config->getOption('vhost')); +// $bunnyConfig['path'] = 'enqueue';//$this->config->getOption('path', $this->config->getOption('vhost')); // } if ($this->config->getHeartbeat()) { @@ -109,7 +109,7 @@ private function establishConnection() $bunnyConfig['tcp_nodelay'] = $this->config->getOption('tcp_nodelay'); } - $this->client = new Client($bunnyConfig); + $this->client = new BunnyClient($bunnyConfig); $this->client->connect(); } diff --git a/pkg/amqp-bunny/BunnyClient.php b/pkg/amqp-bunny/BunnyClient.php new file mode 100644 index 000000000..fbaa0b396 --- /dev/null +++ b/pkg/amqp-bunny/BunnyClient.php @@ -0,0 +1,18 @@ +getMessage() +// } + } +} diff --git a/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php b/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php deleted file mode 100644 index f83202839..000000000 --- a/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php +++ /dev/null @@ -1,140 +0,0 @@ -name = $name; - } - - /** - * {@inheritdoc} - */ - public function addConfiguration(ArrayNodeDefinition $builder) - { - $builder - ->beforeNormalization() - ->ifString() - ->then(function ($v) { - return ['dsn' => $v]; - }) - ->end() - ->children() - ->scalarNode('dsn') - ->info('The connection to AMQP broker set as a string. Other parameters are ignored if set') - ->end() - ->scalarNode('host') - ->defaultValue('localhost') - ->cannotBeEmpty() - ->info('The host to connect too. Note: Max 1024 characters') - ->end() - ->scalarNode('port') - ->defaultValue(5672) - ->cannotBeEmpty() - ->info('Port on the host.') - ->end() - ->scalarNode('user') - ->defaultValue('guest') - ->cannotBeEmpty() - ->info('The user name to use. Note: Max 128 characters.') - ->end() - ->scalarNode('pass') - ->defaultValue('guest') - ->cannotBeEmpty() - ->info('Password. Note: Max 128 characters.') - ->end() - ->scalarNode('vhost') - ->defaultValue('/') - ->cannotBeEmpty() - ->info('The virtual host on the host. Note: Max 128 characters.') - ->end() - ->booleanNode('lazy') - ->defaultTrue() - ->end() - ->enumNode('receive_method') - ->values(['basic_get', 'basic_consume']) - ->defaultValue('basic_get') - ->info('The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher') - ->end() - ->integerNode('heartbeat') - ->defaultValue(0) - ->end() - ; - } - - /** - * {@inheritdoc} - */ - public function createConnectionFactory(ContainerBuilder $container, array $config) - { - $factory = new Definition(AmqpConnectionFactory::class); - $factory->setArguments(isset($config['dsn']) ? [$config['dsn']] : [$config]); - - $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName()); - $container->setDefinition($factoryId, $factory); - - return $factoryId; - } - - /** - * {@inheritdoc} - */ - public function createContext(ContainerBuilder $container, array $config) - { - $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName()); - - $context = new Definition(AmqpContext::class); - $context->setFactory([new Reference($factoryId), 'createContext']); - - $contextId = sprintf('enqueue.transport.%s.context', $this->getName()); - $container->setDefinition($contextId, $context); - - return $contextId; - } - - /** - * {@inheritdoc} - */ - public function createDriver(ContainerBuilder $container, array $config) - { - $driver = new Definition(AmqpDriver::class); - $driver->setArguments([ - new Reference(sprintf('enqueue.transport.%s.context', $this->getName())), - new Reference('enqueue.client.config'), - new Reference('enqueue.client.meta.queue_meta_registry'), - ]); - - $driverId = sprintf('enqueue.client.%s.driver', $this->getName()); - $container->setDefinition($driverId, $driver); - - return $driverId; - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return $this->name; - } -} diff --git a/pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php b/pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php deleted file mode 100644 index 95341671f..000000000 --- a/pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php +++ /dev/null @@ -1,68 +0,0 @@ -children() - ->scalarNode('delay_strategy') - ->defaultValue('dlx') - ->info('The delay strategy to be used. Possible values are "dlx", "delayed_message_plugin" or service id') - ->end() - ; - } - - /** - * {@inheritdoc} - */ - public function createConnectionFactory(ContainerBuilder $container, array $config) - { - $factoryId = parent::createConnectionFactory($container, $config); - - $this->registerDelayStrategy($container, $config, $factoryId, $this->getName()); - - return $factoryId; - } - - /** - * {@inheritdoc} - */ - public function createDriver(ContainerBuilder $container, array $config) - { - $driver = new Definition(RabbitMqDriver::class); - $driver->setArguments([ - new Reference(sprintf('enqueue.transport.%s.context', $this->getName())), - new Reference('enqueue.client.config'), - new Reference('enqueue.client.meta.queue_meta_registry'), - ]); - $driverId = sprintf('enqueue.client.%s.driver', $this->getName()); - $container->setDefinition($driverId, $driver); - - return $driverId; - } -} diff --git a/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php b/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php deleted file mode 100644 index 9b2a68bc2..000000000 --- a/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php +++ /dev/null @@ -1,218 +0,0 @@ -assertClassImplements(TransportFactoryInterface::class, AmqpBunnyTransportFactory::class); - } - - public function testCouldBeConstructedWithDefaultName() - { - $transport = new AmqpBunnyTransportFactory(); - - $this->assertEquals('amqp_bunny', $transport->getName()); - } - - public function testCouldBeConstructedWithCustomName() - { - $transport = new AmqpBunnyTransportFactory('theCustomName'); - - $this->assertEquals('theCustomName', $transport->getName()); - } - - public function testShouldAllowAddConfiguration() - { - $transport = new AmqpBunnyTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - $config = $processor->process($tb->buildTree(), []); - - $this->assertEquals([ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'lazy' => true, - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - ], $config); - } - - public function testShouldAllowAddConfigurationAsString() - { - $transport = new AmqpBunnyTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - $config = $processor->process($tb->buildTree(), ['amqpDSN']); - - $this->assertEquals([ - 'dsn' => 'amqpDSN', - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'lazy' => true, - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - ], $config); - } - - public function testThrowIfInvalidReceiveMethodIsSet() - { - $transport = new AmqpBunnyTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - - $this->expectException(InvalidConfigurationException::class); - $this->expectExceptionMessage('The value "anInvalidMethod" is not allowed for path "foo.receive_method". Permissible values: "basic_get", "basic_consume"'); - $processor->process($tb->buildTree(), [[ - 'receive_method' => 'anInvalidMethod', - ]]); - } - - public function testShouldAllowChangeReceiveMethod() - { - $transport = new AmqpBunnyTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - $config = $processor->process($tb->buildTree(), [[ - 'receive_method' => 'basic_consume', - ]]); - - $this->assertEquals([ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'lazy' => true, - 'receive_method' => 'basic_consume', - 'heartbeat' => 0, - ], $config); - } - - public function testShouldCreateConnectionFactory() - { - $container = new ContainerBuilder(); - - $transport = new AmqpBunnyTransportFactory(); - - $serviceId = $transport->createConnectionFactory($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - ]); - - $this->assertTrue($container->hasDefinition($serviceId)); - $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); - $this->assertSame([[ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - ]], $factory->getArguments()); - } - - public function testShouldCreateConnectionFactoryFromDsnString() - { - $container = new ContainerBuilder(); - - $transport = new AmqpBunnyTransportFactory(); - - $serviceId = $transport->createConnectionFactory($container, [ - 'dsn' => 'theConnectionDSN', - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - ]); - - $this->assertTrue($container->hasDefinition($serviceId)); - $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); - $this->assertSame(['theConnectionDSN'], $factory->getArguments()); - } - - public function testShouldCreateContext() - { - $container = new ContainerBuilder(); - - $transport = new AmqpBunnyTransportFactory(); - - $serviceId = $transport->createContext($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - ]); - - $this->assertEquals('enqueue.transport.amqp_bunny.context', $serviceId); - $this->assertTrue($container->hasDefinition($serviceId)); - - $context = $container->getDefinition('enqueue.transport.amqp_bunny.context'); - $this->assertInstanceOf(Reference::class, $context->getFactory()[0]); - $this->assertEquals('enqueue.transport.amqp_bunny.connection_factory', (string) $context->getFactory()[0]); - $this->assertEquals('createContext', $context->getFactory()[1]); - } - - public function testShouldCreateDriver() - { - $container = new ContainerBuilder(); - - $transport = new AmqpBunnyTransportFactory(); - - $serviceId = $transport->createDriver($container, []); - - $this->assertEquals('enqueue.client.amqp_bunny.driver', $serviceId); - $this->assertTrue($container->hasDefinition($serviceId)); - - $driver = $container->getDefinition($serviceId); - $this->assertSame(AmqpDriver::class, $driver->getClass()); - - $this->assertInstanceOf(Reference::class, $driver->getArgument(0)); - $this->assertEquals('enqueue.transport.amqp_bunny.context', (string) $driver->getArgument(0)); - - $this->assertInstanceOf(Reference::class, $driver->getArgument(1)); - $this->assertEquals('enqueue.client.config', (string) $driver->getArgument(1)); - - $this->assertInstanceOf(Reference::class, $driver->getArgument(2)); - $this->assertEquals('enqueue.client.meta.queue_meta_registry', (string) $driver->getArgument(2)); - } -} diff --git a/pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php b/pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php deleted file mode 100644 index 555ad777e..000000000 --- a/pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php +++ /dev/null @@ -1,137 +0,0 @@ -assertClassImplements(TransportFactoryInterface::class, RabbitMqAmqpBunnyTransportFactory::class); - } - - public function testShouldExtendAmqpTransportFactoryClass() - { - $this->assertClassExtends(AmqpBunnyTransportFactory::class, RabbitMqAmqpBunnyTransportFactory::class); - } - - public function testCouldBeConstructedWithDefaultName() - { - $transport = new RabbitMqAmqpBunnyTransportFactory(); - - $this->assertEquals('rabbitmq_amqp_bunny', $transport->getName()); - } - - public function testCouldBeConstructedWithCustomName() - { - $transport = new RabbitMqAmqpBunnyTransportFactory('theCustomName'); - - $this->assertEquals('theCustomName', $transport->getName()); - } - - public function testShouldAllowAddConfiguration() - { - $transport = new RabbitMqAmqpBunnyTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - $config = $processor->process($tb->buildTree(), []); - - $this->assertEquals([ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'delay_strategy' => 'dlx', - 'lazy' => true, - 'receive_method' => 'basic_get', - 'heartbeat' => 0, - ], $config); - } - - public function testShouldCreateConnectionFactory() - { - $container = new ContainerBuilder(); - - $transport = new RabbitMqAmqpBunnyTransportFactory(); - - $serviceId = $transport->createConnectionFactory($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - 'delay_strategy' => null, - ]); - - $this->assertTrue($container->hasDefinition($serviceId)); - $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); - $this->assertSame([[ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - 'delay_strategy' => null, - ]], $factory->getArguments()); - } - - public function testShouldCreateContext() - { - $container = new ContainerBuilder(); - - $transport = new RabbitMqAmqpBunnyTransportFactory(); - - $serviceId = $transport->createContext($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - 'delay_strategy' => null, - ]); - - $this->assertEquals('enqueue.transport.rabbitmq_amqp_bunny.context', $serviceId); - $this->assertTrue($container->hasDefinition($serviceId)); - - $context = $container->getDefinition('enqueue.transport.rabbitmq_amqp_bunny.context'); - $this->assertInstanceOf(Reference::class, $context->getFactory()[0]); - $this->assertEquals('enqueue.transport.rabbitmq_amqp_bunny.connection_factory', (string) $context->getFactory()[0]); - $this->assertEquals('createContext', $context->getFactory()[1]); - } - - public function testShouldCreateDriver() - { - $container = new ContainerBuilder(); - - $transport = new RabbitMqAmqpBunnyTransportFactory(); - - $serviceId = $transport->createDriver($container, []); - - $this->assertEquals('enqueue.client.rabbitmq_amqp_bunny.driver', $serviceId); - $this->assertTrue($container->hasDefinition($serviceId)); - - $driver = $container->getDefinition($serviceId); - $this->assertSame(RabbitMqDriver::class, $driver->getClass()); - } -} diff --git a/pkg/amqp-ext/AmqpConnectionFactory.php b/pkg/amqp-ext/AmqpConnectionFactory.php index 8a7c02add..18de675e6 100644 --- a/pkg/amqp-ext/AmqpConnectionFactory.php +++ b/pkg/amqp-ext/AmqpConnectionFactory.php @@ -73,7 +73,7 @@ public function createContext() return $context; } - $context = new AmqpContext($this->createExtContext($this->establishConnection()), $this->config['receive_method']); + $context = new AmqpContext($this->createExtContext($this->establishConnection()), $this->config->getOption('receive_method')); $context->setDelayStrategy($this->delayStrategy); $context->setQos($this->config->getQosPrefetchSize(), $this->config->getQosPrefetchCount(), $this->config->isQosGlobal()); diff --git a/pkg/amqp-ext/Symfony/AmqpTransportFactory.php b/pkg/amqp-ext/Symfony/AmqpTransportFactory.php deleted file mode 100644 index e2a80b826..000000000 --- a/pkg/amqp-ext/Symfony/AmqpTransportFactory.php +++ /dev/null @@ -1,152 +0,0 @@ -name = $name; - } - - /** - * {@inheritdoc} - */ - public function addConfiguration(ArrayNodeDefinition $builder) - { - $builder - ->beforeNormalization() - ->ifString() - ->then(function ($v) { - return ['dsn' => $v]; - }) - ->end() - ->children() - ->scalarNode('dsn') - ->info('The connection to AMQP broker set as a string. Other parameters are ignored if set') - ->end() - ->scalarNode('host') - ->defaultValue('localhost') - ->cannotBeEmpty() - ->info('The host to connect too. Note: Max 1024 characters') - ->end() - ->scalarNode('port') - ->defaultValue(5672) - ->cannotBeEmpty() - ->info('Port on the host.') - ->end() - ->scalarNode('user') - ->defaultValue('guest') - ->cannotBeEmpty() - ->info('The user name to use. Note: Max 128 characters.') - ->end() - ->scalarNode('pass') - ->defaultValue('guest') - ->cannotBeEmpty() - ->info('Password. Note: Max 128 characters.') - ->end() - ->scalarNode('vhost') - ->defaultValue('/') - ->cannotBeEmpty() - ->info('The virtual host on the host. Note: Max 128 characters.') - ->end() - ->integerNode('connect_timeout') - ->min(0) - ->info('Connection timeout. Note: 0 or greater seconds. May be fractional.') - ->end() - ->integerNode('read_timeout') - ->min(0) - ->info('Timeout in for income activity. Note: 0 or greater seconds. May be fractional.') - ->end() - ->integerNode('write_timeout') - ->min(0) - ->info('Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional.') - ->end() - ->booleanNode('persisted') - ->defaultFalse() - ->end() - ->booleanNode('lazy') - ->defaultTrue() - ->end() - ->enumNode('receive_method') - ->values(['basic_get', 'basic_consume']) - ->defaultValue('basic_get') - ->info('The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher') - ->end() - ; - } - - /** - * {@inheritdoc} - */ - public function createConnectionFactory(ContainerBuilder $container, array $config) - { - $factory = new Definition(AmqpConnectionFactory::class); - $factory->setArguments(isset($config['dsn']) ? [$config['dsn']] : [$config]); - - $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName()); - $container->setDefinition($factoryId, $factory); - - return $factoryId; - } - - /** - * {@inheritdoc} - */ - public function createContext(ContainerBuilder $container, array $config) - { - $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName()); - - $context = new Definition(AmqpContext::class); - $context->setFactory([new Reference($factoryId), 'createContext']); - - $contextId = sprintf('enqueue.transport.%s.context', $this->getName()); - $container->setDefinition($contextId, $context); - - return $contextId; - } - - /** - * {@inheritdoc} - */ - public function createDriver(ContainerBuilder $container, array $config) - { - $driver = new Definition(AmqpDriver::class); - $driver->setArguments([ - new Reference(sprintf('enqueue.transport.%s.context', $this->getName())), - new Reference('enqueue.client.config'), - new Reference('enqueue.client.meta.queue_meta_registry'), - ]); - - $driverId = sprintf('enqueue.client.%s.driver', $this->getName()); - $container->setDefinition($driverId, $driver); - - return $driverId; - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return $this->name; - } -} diff --git a/pkg/amqp-ext/composer.json b/pkg/amqp-ext/composer.json index ae7306605..7050a0e26 100644 --- a/pkg/amqp-ext/composer.json +++ b/pkg/amqp-ext/composer.json @@ -6,7 +6,7 @@ "license": "MIT", "require": { "php": ">=5.6", - "ext-amqp": "^1.9.1", + "ext-amqp": "^1.6", "queue-interop/amqp-interop": "^0.7@dev", "enqueue/amqp-tools": "^0.8@dev" diff --git a/pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php b/pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php deleted file mode 100644 index 43a88a2da..000000000 --- a/pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php +++ /dev/null @@ -1,68 +0,0 @@ -children() - ->scalarNode('delay_strategy') - ->defaultValue('dlx') - ->info('The delay strategy to be used. Possible values are "dlx", "delayed_message_plugin" or service id') - ->end() - ; - } - - /** - * {@inheritdoc} - */ - public function createConnectionFactory(ContainerBuilder $container, array $config) - { - $factoryId = parent::createConnectionFactory($container, $config); - - $this->registerDelayStrategy($container, $config, $factoryId, $this->getName()); - - return $factoryId; - } - - /** - * {@inheritdoc} - */ - public function createDriver(ContainerBuilder $container, array $config) - { - $driver = new Definition(RabbitMqDriver::class); - $driver->setArguments([ - new Reference(sprintf('enqueue.transport.%s.context', $this->getName())), - new Reference('enqueue.client.config'), - new Reference('enqueue.client.meta.queue_meta_registry'), - ]); - $driverId = sprintf('enqueue.client.%s.driver', $this->getName()); - $container->setDefinition($driverId, $driver); - - return $driverId; - } -} diff --git a/pkg/amqp-lib/Tests/Symfony/AmqpLibTransportFactoryTest.php b/pkg/amqp-lib/Tests/Symfony/AmqpLibTransportFactoryTest.php deleted file mode 100644 index 3aaf3bc6d..000000000 --- a/pkg/amqp-lib/Tests/Symfony/AmqpLibTransportFactoryTest.php +++ /dev/null @@ -1,239 +0,0 @@ -assertClassImplements(TransportFactoryInterface::class, AmqpLibTransportFactory::class); - } - - public function testCouldBeConstructedWithDefaultName() - { - $transport = new AmqpLibTransportFactory(); - - $this->assertEquals('amqp_lib', $transport->getName()); - } - - public function testCouldBeConstructedWithCustomName() - { - $transport = new AmqpLibTransportFactory('theCustomName'); - - $this->assertEquals('theCustomName', $transport->getName()); - } - - public function testShouldAllowAddConfiguration() - { - $transport = new AmqpLibTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - $config = $processor->process($tb->buildTree(), []); - - $this->assertEquals([ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'lazy' => true, - 'receive_method' => 'basic_get', - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'read_timeout' => 3, - 'write_timeout' => 3, - 'stream' => true, - 'insist' => false, - 'keepalive' => false, - 'heartbeat' => 0, - ], $config); - } - - public function testShouldAllowAddConfigurationAsString() - { - $transport = new AmqpLibTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - $config = $processor->process($tb->buildTree(), ['amqpDSN']); - - $this->assertEquals([ - 'dsn' => 'amqpDSN', - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'lazy' => true, - 'receive_method' => 'basic_get', - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'read_timeout' => 3, - 'write_timeout' => 3, - 'stream' => true, - 'insist' => false, - 'keepalive' => false, - 'heartbeat' => 0, - ], $config); - } - - public function testThrowIfInvalidReceiveMethodIsSet() - { - $transport = new AmqpLibTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - - $this->expectException(InvalidConfigurationException::class); - $this->expectExceptionMessage('The value "anInvalidMethod" is not allowed for path "foo.receive_method". Permissible values: "basic_get", "basic_consume"'); - $processor->process($tb->buildTree(), [[ - 'receive_method' => 'anInvalidMethod', - ]]); - } - - public function testShouldAllowChangeReceiveMethod() - { - $transport = new AmqpLibTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - $config = $processor->process($tb->buildTree(), [[ - 'receive_method' => 'basic_consume', - ]]); - - $this->assertEquals([ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'lazy' => true, - 'receive_method' => 'basic_consume', - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'read_timeout' => 3, - 'write_timeout' => 3, - 'stream' => true, - 'insist' => false, - 'keepalive' => false, - 'heartbeat' => 0, - ], $config); - } - - public function testShouldCreateConnectionFactory() - { - $container = new ContainerBuilder(); - - $transport = new AmqpLibTransportFactory(); - - $serviceId = $transport->createConnectionFactory($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - ]); - - $this->assertTrue($container->hasDefinition($serviceId)); - $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); - $this->assertSame([[ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - ]], $factory->getArguments()); - } - - public function testShouldCreateConnectionFactoryFromDsnString() - { - $container = new ContainerBuilder(); - - $transport = new AmqpLibTransportFactory(); - - $serviceId = $transport->createConnectionFactory($container, [ - 'dsn' => 'theConnectionDSN', - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - ]); - - $this->assertTrue($container->hasDefinition($serviceId)); - $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); - $this->assertSame(['theConnectionDSN'], $factory->getArguments()); - } - - public function testShouldCreateContext() - { - $container = new ContainerBuilder(); - - $transport = new AmqpLibTransportFactory(); - - $serviceId = $transport->createContext($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - ]); - - $this->assertEquals('enqueue.transport.amqp_lib.context', $serviceId); - $this->assertTrue($container->hasDefinition($serviceId)); - - $context = $container->getDefinition('enqueue.transport.amqp_lib.context'); - $this->assertInstanceOf(Reference::class, $context->getFactory()[0]); - $this->assertEquals('enqueue.transport.amqp_lib.connection_factory', (string) $context->getFactory()[0]); - $this->assertEquals('createContext', $context->getFactory()[1]); - } - - public function testShouldCreateDriver() - { - $container = new ContainerBuilder(); - - $transport = new AmqpLibTransportFactory(); - - $serviceId = $transport->createDriver($container, []); - - $this->assertEquals('enqueue.client.amqp_lib.driver', $serviceId); - $this->assertTrue($container->hasDefinition($serviceId)); - - $driver = $container->getDefinition($serviceId); - $this->assertSame(AmqpDriver::class, $driver->getClass()); - - $this->assertInstanceOf(Reference::class, $driver->getArgument(0)); - $this->assertEquals('enqueue.transport.amqp_lib.context', (string) $driver->getArgument(0)); - - $this->assertInstanceOf(Reference::class, $driver->getArgument(1)); - $this->assertEquals('enqueue.client.config', (string) $driver->getArgument(1)); - - $this->assertInstanceOf(Reference::class, $driver->getArgument(2)); - $this->assertEquals('enqueue.client.meta.queue_meta_registry', (string) $driver->getArgument(2)); - } -} diff --git a/pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php b/pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php deleted file mode 100644 index b86a57bdf..000000000 --- a/pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php +++ /dev/null @@ -1,144 +0,0 @@ -assertClassImplements(TransportFactoryInterface::class, RabbitMqAmqpLibTransportFactory::class); - } - - public function testShouldExtendAmqpTransportFactoryClass() - { - $this->assertClassExtends(AmqpLibTransportFactory::class, RabbitMqAmqpLibTransportFactory::class); - } - - public function testCouldBeConstructedWithDefaultName() - { - $transport = new RabbitMqAmqpLibTransportFactory(); - - $this->assertEquals('rabbitmq_amqp_lib', $transport->getName()); - } - - public function testCouldBeConstructedWithCustomName() - { - $transport = new RabbitMqAmqpLibTransportFactory('theCustomName'); - - $this->assertEquals('theCustomName', $transport->getName()); - } - - public function testShouldAllowAddConfiguration() - { - $transport = new RabbitMqAmqpLibTransportFactory(); - $tb = new TreeBuilder(); - $rootNode = $tb->root('foo'); - - $transport->addConfiguration($rootNode); - $processor = new Processor(); - $config = $processor->process($tb->buildTree(), []); - - $this->assertEquals([ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'delay_strategy' => 'dlx', - 'lazy' => true, - 'receive_method' => 'basic_get', - 'connection_timeout' => 3.0, - 'read_write_timeout' => 3.0, - 'read_timeout' => 3, - 'write_timeout' => 3, - 'stream' => true, - 'insist' => false, - 'keepalive' => false, - 'heartbeat' => 0, - ], $config); - } - - public function testShouldCreateConnectionFactory() - { - $container = new ContainerBuilder(); - - $transport = new RabbitMqAmqpLibTransportFactory(); - - $serviceId = $transport->createConnectionFactory($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - 'delay_strategy' => null, - ]); - - $this->assertTrue($container->hasDefinition($serviceId)); - $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); - $this->assertSame([[ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - 'delay_strategy' => null, - ]], $factory->getArguments()); - } - - public function testShouldCreateContext() - { - $container = new ContainerBuilder(); - - $transport = new RabbitMqAmqpLibTransportFactory(); - - $serviceId = $transport->createContext($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - 'delay_strategy' => null, - ]); - - $this->assertEquals('enqueue.transport.rabbitmq_amqp_lib.context', $serviceId); - $this->assertTrue($container->hasDefinition($serviceId)); - - $context = $container->getDefinition('enqueue.transport.rabbitmq_amqp_lib.context'); - $this->assertInstanceOf(Reference::class, $context->getFactory()[0]); - $this->assertEquals('enqueue.transport.rabbitmq_amqp_lib.connection_factory', (string) $context->getFactory()[0]); - $this->assertEquals('createContext', $context->getFactory()[1]); - } - - public function testShouldCreateDriver() - { - $container = new ContainerBuilder(); - - $transport = new RabbitMqAmqpLibTransportFactory(); - - $serviceId = $transport->createDriver($container, []); - - $this->assertEquals('enqueue.client.rabbitmq_amqp_lib.driver', $serviceId); - $this->assertTrue($container->hasDefinition($serviceId)); - - $driver = $container->getDefinition($serviceId); - $this->assertSame(RabbitMqDriver::class, $driver->getClass()); - } -} diff --git a/pkg/amqp-tools/ConnectionConfig.php b/pkg/amqp-tools/ConnectionConfig.php index d3a9bfff7..8a844d1b6 100644 --- a/pkg/amqp-tools/ConnectionConfig.php +++ b/pkg/amqp-tools/ConnectionConfig.php @@ -13,7 +13,7 @@ * pass - Password. Note: Max 128 characters * read_timeout - Timeout in for income activity. Note: 0 or greater seconds. May be fractional * write_timeout - Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional - * connect_timeout - Connection timeout. Note: 0 or greater seconds. May be fractional + * connection_timeout - Connection timeout. Note: 0 or greater seconds. May be fractional * heartbeat - how often to send heartbeat. 0 means off * 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 @@ -68,7 +68,7 @@ public function __construct($config = null) 'write_timeout' => 3., 'connection_timeout' => 3., 'heartbeat' => 0, - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_global' => false, 'qos_prefetch_size' => 0, diff --git a/pkg/amqp-tools/Tests/ConnectionConfigTest.php b/pkg/amqp-tools/Tests/ConnectionConfigTest.php index be0094767..8438ac19a 100644 --- a/pkg/amqp-tools/Tests/ConnectionConfigTest.php +++ b/pkg/amqp-tools/Tests/ConnectionConfigTest.php @@ -64,7 +64,7 @@ public function testShouldParseEmptyDsnWithDriverSet() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -89,7 +89,7 @@ public function testShouldParseCustomDsnWithDriverSet() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -125,7 +125,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -145,7 +145,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -165,7 +165,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -185,7 +185,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -205,7 +205,7 @@ public static function provideConfigs() 'read_timeout' => 0., 'write_timeout' => 4, 'connection_timeout' => 20., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -215,7 +215,7 @@ public static function provideConfigs() ]; yield [ - 'amqp://user:pass@host:10000/vhost?persisted=0&lazy=&qos_global=true', + 'amqp://user:pass@host:10000/vhost?persisted=1&lazy=&qos_global=true', [ 'host' => 'host', 'port' => 10000, @@ -225,7 +225,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => false, + 'persisted' => true, 'lazy' => false, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -245,7 +245,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -255,7 +255,7 @@ public static function provideConfigs() ]; yield [ - ['lazy' => false, 'persisted' => 0, 'qos_global' => 1], + ['lazy' => false, 'persisted' => 1, 'qos_global' => 1], [ 'host' => 'localhost', 'port' => 5672, @@ -265,7 +265,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => false, + 'persisted' => true, 'lazy' => false, 'qos_prefetch_size' => 0, 'qos_prefetch_count' => 1, @@ -285,7 +285,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_count' => 123, 'qos_prefetch_size' => 0, @@ -305,7 +305,7 @@ public static function provideConfigs() 'read_timeout' => 3., 'write_timeout' => 3., 'connection_timeout' => 3., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_count' => 123, 'qos_prefetch_size' => 0, @@ -331,7 +331,7 @@ public static function provideConfigs() 'read_timeout' => 20., 'write_timeout' => 30., 'connection_timeout' => 40., - 'persisted' => true, + 'persisted' => false, 'lazy' => true, 'qos_prefetch_count' => 20, 'qos_prefetch_size' => 0, diff --git a/pkg/enqueue-bundle/EnqueueBundle.php b/pkg/enqueue-bundle/EnqueueBundle.php index 9f7400e40..75339c2f2 100644 --- a/pkg/enqueue-bundle/EnqueueBundle.php +++ b/pkg/enqueue-bundle/EnqueueBundle.php @@ -2,15 +2,9 @@ namespace Enqueue\Bundle; -use Enqueue\AmqpBunny\AmqpContext as AmqpBunnyContext; -use Enqueue\AmqpBunny\Symfony\AmqpBunnyTransportFactory; -use Enqueue\AmqpBunny\Symfony\RabbitMqAmqpBunnyTransportFactory; -use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\Symfony\AmqpTransportFactory; -use Enqueue\AmqpExt\Symfony\RabbitMqAmqpTransportFactory; -use Enqueue\AmqpLib\AmqpContext as AmqpLibContext; -use Enqueue\AmqpLib\Symfony\AmqpLibTransportFactory; -use Enqueue\AmqpLib\Symfony\RabbitMqAmqpLibTransportFactory; +use Enqueue\AmqpBunny\AmqpConnectionFactory as AmqpBunnyConnectionFactory; +use Enqueue\AmqpExt\AmqpConnectionFactory as AmqpExtConnectionFactory; +use Enqueue\AmqpLib\AmqpConnectionFactory as AmqpLibConnectionFactory; use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncEventsPass; use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncTransformersPass; use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientExtensionsPass; @@ -21,17 +15,19 @@ use Enqueue\Bundle\DependencyInjection\Compiler\BuildQueueMetaRegistryPass; use Enqueue\Bundle\DependencyInjection\Compiler\BuildTopicMetaSubscribersPass; use Enqueue\Bundle\DependencyInjection\EnqueueExtension; -use Enqueue\Dbal\DbalContext; +use Enqueue\Dbal\DbalConnectionFactory; use Enqueue\Dbal\Symfony\DbalTransportFactory; -use Enqueue\Fs\FsContext; +use Enqueue\Fs\FsConnectionFactory; use Enqueue\Fs\Symfony\FsTransportFactory; -use Enqueue\Redis\RedisContext; +use Enqueue\Redis\RedisConnectionFactory; use Enqueue\Redis\Symfony\RedisTransportFactory; -use Enqueue\Sqs\SqsContext; +use Enqueue\Sqs\SqsConnectionFactory; use Enqueue\Sqs\Symfony\SqsTransportFactory; -use Enqueue\Stomp\StompContext; +use Enqueue\Stomp\StompConnectionFactory; use Enqueue\Stomp\Symfony\RabbitMqStompTransportFactory; use Enqueue\Stomp\Symfony\StompTransportFactory; +use Enqueue\Symfony\AmqpTransportFactory; +use Enqueue\Symfony\RabbitMqAmqpTransportFactory; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -54,40 +50,40 @@ public function build(ContainerBuilder $container) /** @var EnqueueExtension $extension */ $extension = $container->getExtension('enqueue'); - if (class_exists(StompContext::class)) { + if (class_exists(StompConnectionFactory::class)) { $extension->addTransportFactory(new StompTransportFactory()); $extension->addTransportFactory(new RabbitMqStompTransportFactory()); } - if (class_exists(AmqpContext::class)) { - $extension->addTransportFactory(new AmqpTransportFactory()); - $extension->addTransportFactory(new RabbitMqAmqpTransportFactory()); + if (class_exists(AmqpExtConnectionFactory::class)) { + $extension->addTransportFactory(new AmqpTransportFactory(AmqpExtConnectionFactory::class, 'amqp_ext')); + $extension->addTransportFactory(new RabbitMqAmqpTransportFactory(AmqpExtConnectionFactory::class, 'rabbitmq_amqp_ext')); } - if (class_exists(AmqpLibContext::class)) { - $extension->addTransportFactory(new AmqpLibTransportFactory()); - $extension->addTransportFactory(new RabbitMqAmqpLibTransportFactory()); + if (class_exists(AmqpLibConnectionFactory::class)) { + $extension->addTransportFactory(new AmqpTransportFactory(AmqpLibConnectionFactory::class, 'amqp_lib')); + $extension->addTransportFactory(new RabbitMqAmqpTransportFactory(AmqpLibConnectionFactory::class, 'rabbitmq_amqp_lib')); } - if (class_exists(FsContext::class)) { + if (class_exists(FsConnectionFactory::class)) { $extension->addTransportFactory(new FsTransportFactory()); } - if (class_exists(RedisContext::class)) { + if (class_exists(RedisConnectionFactory::class)) { $extension->addTransportFactory(new RedisTransportFactory()); } - if (class_exists(DbalContext::class)) { + if (class_exists(DbalConnectionFactory::class)) { $extension->addTransportFactory(new DbalTransportFactory()); } - if (class_exists(SqsContext::class)) { + if (class_exists(SqsConnectionFactory::class)) { $extension->addTransportFactory(new SqsTransportFactory()); } - if (class_exists(AmqpBunnyContext::class)) { - $extension->addTransportFactory(new AmqpBunnyTransportFactory()); - $extension->addTransportFactory(new RabbitMqAmqpBunnyTransportFactory()); + if (class_exists(AmqpBunnyConnectionFactory::class)) { + $extension->addTransportFactory(new AmqpTransportFactory(AmqpBunnyConnectionFactory::class, 'amqp_bunny')); + $extension->addTransportFactory(new RabbitMqAmqpTransportFactory(AmqpBunnyConnectionFactory::class, 'rabbitmq_amqp_bunny')); } $container->addCompilerPass(new AsyncEventsPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); diff --git a/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php b/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php index da103744c..3011bf246 100644 --- a/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php +++ b/pkg/enqueue-bundle/Tests/Functional/UseCasesTest.php @@ -23,10 +23,10 @@ public function setUp() public function provideEnqueueConfigs() { - yield 'amqp' => [[ + yield 'amqp_ext' => [[ 'transport' => [ - 'default' => 'amqp', - 'amqp' => [ + 'default' => 'amqp_ext', + 'amqp_ext' => [ 'host' => getenv('SYMFONY__RABBITMQ__HOST'), 'port' => getenv('SYMFONY__RABBITMQ__AMQP__PORT'), 'user' => getenv('SYMFONY__RABBITMQ__USER'), @@ -39,8 +39,8 @@ public function provideEnqueueConfigs() yield 'amqp_dsn' => [[ 'transport' => [ - 'default' => 'amqp', - 'amqp' => getenv('AMQP_DSN'), + 'default' => 'amqp_ext', + 'amqp_ext' => getenv('AMQP_DSN'), ], ]]; diff --git a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php index 3b8d69a9d..111155db8 100644 --- a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php +++ b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php @@ -2,12 +2,9 @@ namespace Enqueue\Bundle\Tests\Unit; -use Enqueue\AmqpBunny\Symfony\AmqpBunnyTransportFactory; -use Enqueue\AmqpBunny\Symfony\RabbitMqAmqpBunnyTransportFactory; -use Enqueue\AmqpExt\Symfony\AmqpTransportFactory; -use Enqueue\AmqpExt\Symfony\RabbitMqAmqpTransportFactory; -use Enqueue\AmqpLib\Symfony\AmqpLibTransportFactory; -use Enqueue\AmqpLib\Symfony\RabbitMqAmqpLibTransportFactory; +use Enqueue\AmqpBunny\AmqpConnectionFactory as AmqpBunnyConnectionFactory; +use Enqueue\AmqpExt\AmqpConnectionFactory as AmqpExtConnectionFactory; +use Enqueue\AmqpLib\AmqpConnectionFactory as AmqpLibConnectionFactory; use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientExtensionsPass; use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientRoutingPass; use Enqueue\Bundle\DependencyInjection\Compiler\BuildConsumptionExtensionsPass; @@ -23,6 +20,8 @@ use Enqueue\Sqs\Symfony\SqsTransportFactory; use Enqueue\Stomp\Symfony\RabbitMqStompTransportFactory; use Enqueue\Stomp\Symfony\StompTransportFactory; +use Enqueue\Symfony\AmqpTransportFactory; +use Enqueue\Symfony\RabbitMqAmqpTransportFactory; use Enqueue\Test\ClassExtensionTrait; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -114,7 +113,7 @@ public function testShouldRegisterStompAndRabbitMqStompTransportFactories() $bundle->build($container); } - public function testShouldRegisterAmqpAndRabbitMqAmqpTransportFactories() + public function testShouldRegisterAmqpExtAndRabbitMqAmqpExtTransportFactories() { $extensionMock = $this->createEnqueueExtensionMock(); @@ -125,11 +124,17 @@ public function testShouldRegisterAmqpAndRabbitMqAmqpTransportFactories() ->expects($this->at(2)) ->method('addTransportFactory') ->with($this->isInstanceOf(AmqpTransportFactory::class)) + ->willReturnCallback(function (AmqpTransportFactory $factory) { + $this->assertSame(AmqpExtConnectionFactory::class, $factory->getAmqpConnectionFactoryClass()); + }) ; $extensionMock ->expects($this->at(3)) ->method('addTransportFactory') ->with($this->isInstanceOf(RabbitMqAmqpTransportFactory::class)) + ->willReturnCallback(function (AmqpTransportFactory $factory) { + $this->assertSame(AmqpExtConnectionFactory::class, $factory->getAmqpConnectionFactoryClass()); + }) ; $bundle = new EnqueueBundle(); @@ -146,12 +151,18 @@ public function testShouldRegisterAmqpLibAndRabbitMqAmqpLibTransportFactories() $extensionMock ->expects($this->at(4)) ->method('addTransportFactory') - ->with($this->isInstanceOf(AmqpLibTransportFactory::class)) + ->with($this->isInstanceOf(AmqpTransportFactory::class)) + ->willReturnCallback(function (AmqpTransportFactory $factory) { + $this->assertSame(AmqpLibConnectionFactory::class, $factory->getAmqpConnectionFactoryClass()); + }) ; $extensionMock ->expects($this->at(5)) ->method('addTransportFactory') - ->with($this->isInstanceOf(RabbitMqAmqpLibTransportFactory::class)) + ->with($this->isInstanceOf(RabbitMqAmqpTransportFactory::class)) + ->willReturnCallback(function (AmqpTransportFactory $factory) { + $this->assertSame(AmqpLibConnectionFactory::class, $factory->getAmqpConnectionFactoryClass()); + }) ; $bundle = new EnqueueBundle(); @@ -236,12 +247,18 @@ public function testShouldRegisterAmqpBunnyTransportFactory() $extensionMock ->expects($this->at(10)) ->method('addTransportFactory') - ->with($this->isInstanceOf(AmqpBunnyTransportFactory::class)) + ->with($this->isInstanceOf(AmqpTransportFactory::class)) + ->willReturnCallback(function (AmqpTransportFactory $factory) { + $this->assertSame(AmqpBunnyConnectionFactory::class, $factory->getAmqpConnectionFactoryClass()); + }) ; $extensionMock ->expects($this->at(11)) ->method('addTransportFactory') - ->with($this->isInstanceOf(RabbitMqAmqpBunnyTransportFactory::class)) + ->with($this->isInstanceOf(RabbitMqAmqpTransportFactory::class)) + ->willReturnCallback(function (AmqpTransportFactory $factory) { + $this->assertSame(AmqpBunnyConnectionFactory::class, $factory->getAmqpConnectionFactoryClass()); + }) ; $bundle = new EnqueueBundle(); diff --git a/pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php b/pkg/enqueue/Symfony/AmqpTransportFactory.php similarity index 64% rename from pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php rename to pkg/enqueue/Symfony/AmqpTransportFactory.php index f2fbacdf5..bef8dea37 100644 --- a/pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php +++ b/pkg/enqueue/Symfony/AmqpTransportFactory.php @@ -1,29 +1,33 @@ amqpConnectionFactoryClass = $amqpConnectionFactoryClass; $this->name = $name; } @@ -41,71 +45,58 @@ public function addConfiguration(ArrayNodeDefinition $builder) ->end() ->children() ->scalarNode('dsn') - ->info('The connection to AMQP broker set as a string. Other parameters are ignored if set') + ->info('The connection to AMQP broker set as a string. Other parameters could be used as defaults') ->end() ->scalarNode('host') - ->defaultValue('localhost') - ->cannotBeEmpty() ->info('The host to connect too. Note: Max 1024 characters') ->end() ->scalarNode('port') - ->defaultValue(5672) - ->cannotBeEmpty() ->info('Port on the host.') ->end() ->scalarNode('user') - ->defaultValue('guest') - ->cannotBeEmpty() ->info('The user name to use. Note: Max 128 characters.') ->end() ->scalarNode('pass') - ->defaultValue('guest') - ->cannotBeEmpty() ->info('Password. Note: Max 128 characters.') ->end() ->scalarNode('vhost') - ->defaultValue('/') - ->cannotBeEmpty() ->info('The virtual host on the host. Note: Max 128 characters.') ->end() - ->integerNode('connection_timeout') - ->defaultValue(3.0) + ->floatNode('connection_timeout') ->min(0) ->info('Connection timeout. Note: 0 or greater seconds. May be fractional.') ->end() - ->integerNode('read_write_timeout') - ->defaultValue(3.0) - ->min(0) - ->end() - ->integerNode('read_timeout') - ->defaultValue(3) + ->floatNode('read_timeout') ->min(0) ->info('Timeout in for income activity. Note: 0 or greater seconds. May be fractional.') ->end() - ->integerNode('write_timeout') - ->defaultValue(3) + ->floatNode('write_timeout') ->min(0) ->info('Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional.') ->end() - ->booleanNode('lazy') - ->defaultTrue() - ->end() - ->booleanNode('stream') - ->defaultTrue() - ->end() - ->booleanNode('insist') - ->defaultFalse() - ->end() - ->booleanNode('keepalive') - ->defaultFalse() + ->floatNode('heartbeat') + ->min(0) + ->info('How often to send heartbeat. 0 means off.') ->end() + ->booleanNode('persisted')->end() + ->booleanNode('lazy')->end() ->enumNode('receive_method') ->values(['basic_get', 'basic_consume']) - ->defaultValue('basic_get') ->info('The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher') ->end() - ->integerNode('heartbeat') - ->defaultValue(0) + ->floatNode('qos_prefetch_size') + ->min(0) + ->info('The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit"') + ->end() + ->floatNode('qos_prefetch_count') + ->min(0) + ->info('Specifies a prefetch window in terms of whole messages') + ->end() + ->booleanNode('qos_global') + ->info('If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection.') + ->end() + ->variableNode('driver_options') + ->info('The options that are specific to the amqp transport you chose. For example amqp+lib have insist, keepalive, stream options. amqp+bunny has tcp_nodelay extra option.') ->end() ; } @@ -115,8 +106,15 @@ public function addConfiguration(ArrayNodeDefinition $builder) */ public function createConnectionFactory(ContainerBuilder $container, array $config) { - $factory = new Definition(AmqpConnectionFactory::class); - $factory->setArguments(isset($config['dsn']) ? [$config['dsn']] : [$config]); + if (array_key_exists('driver_options', $config) && is_array($config['driver_options'])) { + $driverOptions = $config['driver_options']; + unset($config['driver_options']); + + $config = array_replace($driverOptions, $config); + } + + $factory = new Definition($this->amqpConnectionFactoryClass); + $factory->setArguments([$config]); $factoryId = sprintf('enqueue.transport.%s.connection_factory', $this->getName()); $container->setDefinition($factoryId, $factory); @@ -165,4 +163,12 @@ public function getName() { return $this->name; } + + /** + * @return string + */ + public function getAmqpConnectionFactoryClass() + { + return $this->amqpConnectionFactoryClass; + } } diff --git a/pkg/enqueue/Symfony/DefaultTransportFactory.php b/pkg/enqueue/Symfony/DefaultTransportFactory.php index 2e3344488..5911dc43d 100644 --- a/pkg/enqueue/Symfony/DefaultTransportFactory.php +++ b/pkg/enqueue/Symfony/DefaultTransportFactory.php @@ -2,12 +2,6 @@ namespace Enqueue\Symfony; -use Enqueue\AmqpBunny\AmqpConnectionFactory as AmqpBunnyConnectionFactory; -use Enqueue\AmqpBunny\Symfony\AmqpBunnyTransportFactory; -use Enqueue\AmqpExt\AmqpConnectionFactory as AmqpExtConnectionFactory; -use Enqueue\AmqpExt\Symfony\AmqpTransportFactory; -use Enqueue\AmqpLib\AmqpConnectionFactory as AmqpLibConnectionFactory; -use Enqueue\AmqpLib\Symfony\AmqpLibTransportFactory; use Enqueue\Dbal\DbalConnectionFactory; use Enqueue\Dbal\Symfony\DbalTransportFactory; use Enqueue\Fs\FsConnectionFactory; @@ -22,6 +16,7 @@ use Enqueue\Sqs\Symfony\SqsTransportFactory; use Enqueue\Stomp\StompConnectionFactory; use Enqueue\Stomp\Symfony\StompTransportFactory; +use Interop\Amqp\AmqpConnectionFactory; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use function Enqueue\dsn_to_connection_factory; @@ -181,16 +176,8 @@ private function findFactory($dsn) { $factory = dsn_to_connection_factory($dsn); - if ($factory instanceof AmqpExtConnectionFactory) { - return new AmqpTransportFactory('default_amqp_ext'); - } - - if ($factory instanceof AmqpLibConnectionFactory) { - return new AmqpLibTransportFactory('default_amqp_lib'); - } - - if ($factory instanceof AmqpBunnyConnectionFactory) { - return new AmqpBunnyTransportFactory('default_amqp_bunny'); + if ($factory instanceof AmqpConnectionFactory) { + return new AmqpTransportFactory(get_class($factory), 'default_amqp'); } if ($factory instanceof FsConnectionFactory) { diff --git a/pkg/amqp-ext/Symfony/RabbitMqAmqpTransportFactory.php b/pkg/enqueue/Symfony/RabbitMqAmqpTransportFactory.php similarity index 89% rename from pkg/amqp-ext/Symfony/RabbitMqAmqpTransportFactory.php rename to pkg/enqueue/Symfony/RabbitMqAmqpTransportFactory.php index 8ab200e14..cfc4d2413 100644 --- a/pkg/amqp-ext/Symfony/RabbitMqAmqpTransportFactory.php +++ b/pkg/enqueue/Symfony/RabbitMqAmqpTransportFactory.php @@ -1,6 +1,6 @@ createAmqpConnectionFactoryClass()); $this->assertEquals('amqp', $transport->getName()); } public function testCouldBeConstructedWithCustomName() { - $transport = new AmqpTransportFactory('theCustomName'); + $transport = new AmqpTransportFactory($this->createAmqpConnectionFactoryClass(), 'theCustomName'); $this->assertEquals('theCustomName', $transport->getName()); } public function testShouldAllowAddConfiguration() { - $transport = new AmqpTransportFactory(); + $transport = new AmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $tb = new TreeBuilder(); $rootNode = $tb->root('foo'); $transport->addConfiguration($rootNode); $processor = new Processor(); - $config = $processor->process($tb->buildTree(), []); + $config = $processor->process($tb->buildTree(), [[ + 'host' => 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'vhost' => '/', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'heartbeat' => 0, + 'persisted' => false, + 'lazy' => true, + 'qos_global' => false, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'receive_method' => 'basic_get', + ]]); $this->assertEquals([ 'host' => 'localhost', @@ -53,15 +69,45 @@ public function testShouldAllowAddConfiguration() 'user' => 'guest', 'pass' => 'guest', 'vhost' => '/', + 'read_timeout' => 3., + 'write_timeout' => 3., + 'connection_timeout' => 3., + 'heartbeat' => 0, 'persisted' => false, 'lazy' => true, + 'qos_global' => false, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, 'receive_method' => 'basic_get', ], $config); } + public function testShouldAllowAddConfigurationWithDriverOptions() + { + $transport = new AmqpTransportFactory($this->createAmqpConnectionFactoryClass()); + $tb = new TreeBuilder(); + $rootNode = $tb->root('foo'); + + $transport->addConfiguration($rootNode); + $processor = new Processor(); + $config = $processor->process($tb->buildTree(), [[ + 'host' => 'localhost', + 'driver_options' => [ + 'foo' => 'fooVal', + ], + ]]); + + $this->assertEquals([ + 'host' => 'localhost', + 'driver_options' => [ + 'foo' => 'fooVal', + ], + ], $config); + } + public function testShouldAllowAddConfigurationAsString() { - $transport = new AmqpTransportFactory(); + $transport = new AmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $tb = new TreeBuilder(); $rootNode = $tb->root('foo'); @@ -71,20 +117,12 @@ public function testShouldAllowAddConfigurationAsString() $this->assertEquals([ 'dsn' => 'amqpDSN', - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - 'lazy' => true, - 'receive_method' => 'basic_get', ], $config); } public function testThrowIfInvalidReceiveMethodIsSet() { - $transport = new AmqpTransportFactory(); + $transport = new AmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $tb = new TreeBuilder(); $rootNode = $tb->root('foo'); @@ -100,7 +138,7 @@ public function testThrowIfInvalidReceiveMethodIsSet() public function testShouldAllowChangeReceiveMethod() { - $transport = new AmqpTransportFactory(); + $transport = new AmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $tb = new TreeBuilder(); $rootNode = $tb->root('foo'); @@ -111,50 +149,72 @@ public function testShouldAllowChangeReceiveMethod() ]]); $this->assertEquals([ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - 'lazy' => true, 'receive_method' => 'basic_consume', ], $config); } - public function testShouldCreateConnectionFactory() + public function testShouldCreateConnectionFactoryForEmptyConfig() { $container = new ContainerBuilder(); - $transport = new AmqpTransportFactory(); + $expectedClass = $this->createAmqpConnectionFactoryClass(); + + $transport = new AmqpTransportFactory($expectedClass); + + $serviceId = $transport->createConnectionFactory($container, []); + + $this->assertTrue($container->hasDefinition($serviceId)); + $factory = $container->getDefinition($serviceId); + $this->assertEquals($expectedClass, $factory->getClass()); + $this->assertSame([[]], $factory->getArguments()); + } + + public function testShouldCreateConnectionFactoryFromDsnString() + { + $container = new ContainerBuilder(); + + $expectedClass = $this->createAmqpConnectionFactoryClass(); + + $transport = new AmqpTransportFactory($expectedClass); $serviceId = $transport->createConnectionFactory($container, [ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, + 'dsn' => 'theConnectionDSN', ]); $this->assertTrue($container->hasDefinition($serviceId)); $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); - $this->assertSame([[ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, - ]], $factory->getArguments()); + $this->assertEquals($expectedClass, $factory->getClass()); + $this->assertSame([['dsn' => 'theConnectionDSN']], $factory->getArguments()); } - public function testShouldCreateConnectionFactoryFromDsnString() + public function testShouldCreateConnectionFactoryAndMergeDriverOptionsIfSet() + { + $container = new ContainerBuilder(); + + $expectedClass = $this->createAmqpConnectionFactoryClass(); + + $transport = new AmqpTransportFactory($expectedClass); + + $serviceId = $transport->createConnectionFactory($container, [ + 'host' => 'aHost', + 'driver_options' => [ + 'foo' => 'fooVal', + ], + ]); + + $this->assertTrue($container->hasDefinition($serviceId)); + $factory = $container->getDefinition($serviceId); + $this->assertEquals($expectedClass, $factory->getClass()); + $this->assertSame([['foo' => 'fooVal', 'host' => 'aHost']], $factory->getArguments()); + } + + public function testShouldCreateConnectionFactoryFromDsnStringPlushArrayOptions() { $container = new ContainerBuilder(); - $transport = new AmqpTransportFactory(); + $expectedClass = $this->createAmqpConnectionFactoryClass(); + + $transport = new AmqpTransportFactory($expectedClass); $serviceId = $transport->createConnectionFactory($container, [ 'dsn' => 'theConnectionDSN', @@ -168,15 +228,23 @@ public function testShouldCreateConnectionFactoryFromDsnString() $this->assertTrue($container->hasDefinition($serviceId)); $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); - $this->assertSame(['theConnectionDSN'], $factory->getArguments()); + $this->assertEquals($expectedClass, $factory->getClass()); + $this->assertSame([[ + 'dsn' => 'theConnectionDSN', + 'host' => 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'vhost' => '/', + 'persisted' => false, + ]], $factory->getArguments()); } public function testShouldCreateContext() { $container = new ContainerBuilder(); - $transport = new AmqpTransportFactory(); + $transport = new AmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $serviceId = $transport->createContext($container, [ 'host' => 'localhost', @@ -200,7 +268,7 @@ public function testShouldCreateDriver() { $container = new ContainerBuilder(); - $transport = new AmqpTransportFactory(); + $transport = new AmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $serviceId = $transport->createDriver($container, []); @@ -219,4 +287,12 @@ public function testShouldCreateDriver() $this->assertInstanceOf(Reference::class, $driver->getArgument(2)); $this->assertEquals('enqueue.client.meta.queue_meta_registry', (string) $driver->getArgument(2)); } + + /** + * @return string + */ + private function createAmqpConnectionFactoryClass() + { + return $this->getMockClass(AmqpConnectionFactory::class); + } } diff --git a/pkg/enqueue/Tests/Symfony/DefaultTransportFactoryTest.php b/pkg/enqueue/Tests/Symfony/DefaultTransportFactoryTest.php index 1c7b0bd5c..7f84d6d04 100644 --- a/pkg/enqueue/Tests/Symfony/DefaultTransportFactoryTest.php +++ b/pkg/enqueue/Tests/Symfony/DefaultTransportFactoryTest.php @@ -250,11 +250,11 @@ public function testShouldCreateDriverFromDsn($dsn, $expectedName) public static function provideDSNs() { - yield ['amqp+ext:', 'default_amqp_ext']; + yield ['amqp+ext:', 'default_amqp']; - yield ['amqp+lib:', 'default_amqp_lib']; + yield ['amqp+lib:', 'default_amqp']; - yield ['amqp+bunny:', 'default_amqp_bunny']; + yield ['amqp+bunny:', 'default_amqp']; yield ['null:', 'default_null']; diff --git a/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php b/pkg/enqueue/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php similarity index 77% rename from pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php rename to pkg/enqueue/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php index 31853492a..9d16eb540 100644 --- a/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php +++ b/pkg/enqueue/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php @@ -1,13 +1,13 @@ createAmqpConnectionFactoryClass()); $this->assertEquals('rabbitmq_amqp', $transport->getName()); } public function testCouldBeConstructedWithCustomName() { - $transport = new RabbitMqAmqpTransportFactory('theCustomName'); + $transport = new RabbitMqAmqpTransportFactory($this->createAmqpConnectionFactoryClass(), 'theCustomName'); $this->assertEquals('theCustomName', $transport->getName()); } public function testShouldAllowAddConfiguration() { - $transport = new RabbitMqAmqpTransportFactory(); + $transport = new RabbitMqAmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $tb = new TreeBuilder(); $rootNode = $tb->root('foo'); @@ -53,15 +53,7 @@ public function testShouldAllowAddConfiguration() $config = $processor->process($tb->buildTree(), []); $this->assertEquals([ - 'host' => 'localhost', - 'port' => 5672, - 'user' => 'guest', - 'pass' => 'guest', - 'vhost' => '/', - 'persisted' => false, 'delay_strategy' => 'dlx', - 'lazy' => true, - 'receive_method' => 'basic_get', ], $config); } @@ -69,7 +61,9 @@ public function testShouldCreateConnectionFactory() { $container = new ContainerBuilder(); - $transport = new RabbitMqAmqpTransportFactory(); + $expectedClass = $this->createAmqpConnectionFactoryClass(); + + $transport = new RabbitMqAmqpTransportFactory($expectedClass); $serviceId = $transport->createConnectionFactory($container, [ 'host' => 'localhost', @@ -83,7 +77,7 @@ public function testShouldCreateConnectionFactory() $this->assertTrue($container->hasDefinition($serviceId)); $factory = $container->getDefinition($serviceId); - $this->assertEquals(AmqpConnectionFactory::class, $factory->getClass()); + $this->assertEquals($expectedClass, $factory->getClass()); $this->assertSame([[ 'host' => 'localhost', 'port' => 5672, @@ -99,7 +93,7 @@ public function testShouldCreateContext() { $container = new ContainerBuilder(); - $transport = new RabbitMqAmqpTransportFactory(); + $transport = new RabbitMqAmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $serviceId = $transport->createContext($container, [ 'host' => 'localhost', @@ -124,7 +118,7 @@ public function testShouldCreateDriver() { $container = new ContainerBuilder(); - $transport = new RabbitMqAmqpTransportFactory(); + $transport = new RabbitMqAmqpTransportFactory($this->createAmqpConnectionFactoryClass()); $serviceId = $transport->createDriver($container, []); @@ -134,4 +128,12 @@ public function testShouldCreateDriver() $driver = $container->getDefinition($serviceId); $this->assertSame(RabbitMqDriver::class, $driver->getClass()); } + + /** + * @return string + */ + private function createAmqpConnectionFactoryClass() + { + return $this->getMockClass(AmqpConnectionFactory::class); + } } From efd269fc65a27a720717c7fb0bfd4222990b5fac Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Sat, 14 Oct 2017 20:14:23 +0300 Subject: [PATCH 4/6] [client] fix simple client tests --- pkg/simple-client/SimpleClient.php | 32 ++++++++++++++----- .../Tests/Functional/SimpleClientTest.php | 12 +++---- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/pkg/simple-client/SimpleClient.php b/pkg/simple-client/SimpleClient.php index 14afa8e54..0abfc74b9 100644 --- a/pkg/simple-client/SimpleClient.php +++ b/pkg/simple-client/SimpleClient.php @@ -2,8 +2,9 @@ namespace Enqueue\SimpleClient; -use Enqueue\AmqpExt\Symfony\AmqpTransportFactory; -use Enqueue\AmqpExt\Symfony\RabbitMqAmqpTransportFactory; +use Enqueue\AmqpBunny\AmqpConnectionFactory as AmqpBunnyConnectionFactory; +use Enqueue\AmqpExt\AmqpConnectionFactory as AmqpExtConnectionFactory; +use Enqueue\AmqpLib\AmqpConnectionFactory as AmqpLibConnectionFactory; use Enqueue\Client\ArrayProcessorRegistry; use Enqueue\Client\Config; use Enqueue\Client\DelegateProcessor; @@ -22,7 +23,9 @@ use Enqueue\Sqs\Symfony\SqsTransportFactory; use Enqueue\Stomp\Symfony\RabbitMqStompTransportFactory; use Enqueue\Stomp\Symfony\StompTransportFactory; +use Enqueue\Symfony\AmqpTransportFactory; use Enqueue\Symfony\DefaultTransportFactory; +use Enqueue\Symfony\RabbitMqAmqpTransportFactory; use Interop\Queue\PsrContext; use Interop\Queue\PsrProcessor; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -46,8 +49,8 @@ final class SimpleClient * *$config = [ * 'transport' => [ - * 'default' => 'amqp', - * 'amqp' => [], // amqp options here + * 'default' => 'amqp_ext', + * 'amqp_ext' => [], // amqp options here * ], * ] * @@ -55,8 +58,8 @@ final class SimpleClient * * $config = [ * 'transport' => [ - * 'default' => 'amqp', - * 'amqp' => [], + * 'default' => 'amqp_ext', + * 'amqp_ext' => [], * .... * ], * 'client' => [ @@ -275,8 +278,6 @@ private function buildContainerExtension() { $map = [ 'default' => DefaultTransportFactory::class, - 'amqp' => AmqpTransportFactory::class, - 'rabbitmq_amqp' => RabbitMqAmqpTransportFactory::class, 'dbal' => DbalTransportFactory::class, 'fs' => FsTransportFactory::class, 'redis' => RedisTransportFactory::class, @@ -293,6 +294,21 @@ private function buildContainerExtension() } } + if (class_exists(AmqpExtConnectionFactory::class)) { + $extension->addTransportFactory(new AmqpTransportFactory(AmqpExtConnectionFactory::class, 'amqp_ext')); + $extension->addTransportFactory(new RabbitMqAmqpTransportFactory(AmqpExtConnectionFactory::class, 'rabbitmq_amqp_ext')); + } + + if (class_exists(AmqpLibConnectionFactory::class)) { + $extension->addTransportFactory(new AmqpTransportFactory(AmqpLibConnectionFactory::class, 'amqp_lib')); + $extension->addTransportFactory(new RabbitMqAmqpTransportFactory(AmqpLibConnectionFactory::class, 'rabbitmq_amqp_lib')); + } + + if (class_exists(AmqpBunnyConnectionFactory::class)) { + $extension->addTransportFactory(new AmqpTransportFactory(AmqpBunnyConnectionFactory::class, 'amqp_bunny')); + $extension->addTransportFactory(new RabbitMqAmqpTransportFactory(AmqpBunnyConnectionFactory::class, 'rabbitmq_amqp_bunny')); + } + return $extension; } diff --git a/pkg/simple-client/Tests/Functional/SimpleClientTest.php b/pkg/simple-client/Tests/Functional/SimpleClientTest.php index 35dfd979c..503b0b49c 100644 --- a/pkg/simple-client/Tests/Functional/SimpleClientTest.php +++ b/pkg/simple-client/Tests/Functional/SimpleClientTest.php @@ -33,8 +33,8 @@ public function transportConfigDataProvider() { yield 'amqp' => [[ 'transport' => [ - 'default' => 'amqp', - 'amqp' => [ + 'default' => 'amqp_ext', + 'amqp_ext' => [ 'host' => getenv('SYMFONY__RABBITMQ__HOST'), 'port' => getenv('SYMFONY__RABBITMQ__AMQP__PORT'), 'user' => getenv('SYMFONY__RABBITMQ__USER'), @@ -48,8 +48,8 @@ public function transportConfigDataProvider() yield 'amqp_dsn' => [[ 'transport' => [ - 'default' => 'amqp', - 'amqp' => getenv('AMQP_DSN'), + 'default' => 'amqp_ext', + 'amqp_ext' => getenv('AMQP_DSN'), ], ]]; @@ -61,8 +61,8 @@ public function transportConfigDataProvider() yield [[ 'transport' => [ - 'default' => 'rabbitmq_amqp', - 'rabbitmq_amqp' => [ + 'default' => 'rabbitmq_amqp_ext', + 'rabbitmq_amqp_ext' => [ 'host' => getenv('SYMFONY__RABBITMQ__HOST'), 'port' => getenv('SYMFONY__RABBITMQ__AMQP__PORT'), 'user' => getenv('SYMFONY__RABBITMQ__USER'), From 040eb5a407cdd08bfc61d2878294041d6d3988f9 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Sat, 14 Oct 2017 20:14:36 +0300 Subject: [PATCH 5/6] [doc] upd config ref doc. --- docs/bundle/config_reference.md | 249 ++++++++++++++++++++++---------- 1 file changed, 175 insertions(+), 74 deletions(-) diff --git a/docs/bundle/config_reference.md b/docs/bundle/config_reference.md index 2dd7a888e..3164e59bc 100644 --- a/docs/bundle/config_reference.md +++ b/docs/bundle/config_reference.md @@ -38,149 +38,201 @@ enqueue: # The option tells whether RabbitMQ broker has delay plugin installed or not delay_plugin_installed: false - amqp: + amqp_ext: - # The connection to AMQP broker set as a string. Other parameters are ignored if set + # The connection to AMQP broker set as a string. Other parameters could be used as defaults dsn: ~ # The host to connect too. Note: Max 1024 characters - host: localhost + host: ~ # Port on the host. - port: 5672 + port: ~ # The user name to use. Note: Max 128 characters. - user: guest + user: ~ # Password. Note: Max 128 characters. - pass: guest + pass: ~ # The virtual host on the host. Note: Max 128 characters. - vhost: / + vhost: ~ # Connection timeout. Note: 0 or greater seconds. May be fractional. - connect_timeout: ~ + connection_timeout: ~ # Timeout in for income activity. Note: 0 or greater seconds. May be fractional. read_timeout: ~ # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. write_timeout: ~ - persisted: false - lazy: true + + # How often to send heartbeat. 0 means off. + heartbeat: ~ + persisted: ~ + lazy: ~ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher - receive_method: basic_get # One of "basic_get"; "basic_consume" - rabbitmq_amqp: + receive_method: ~ # One of "basic_get"; "basic_consume" + + # The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit" + qos_prefetch_size: ~ + + # Specifies a prefetch window in terms of whole messages + qos_prefetch_count: ~ + + # If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection. + qos_global: ~ + + # The options that are specific to the amqp transport you chose. For example amqp+lib have insist, keepalive, stream options. amqp+bunny has tcp_nodelay extra option. + driver_options: ~ + rabbitmq_amqp_ext: - # The connection to AMQP broker set as a string. Other parameters are ignored if set + # The connection to AMQP broker set as a string. Other parameters could be used as defaults dsn: ~ # The host to connect too. Note: Max 1024 characters - host: localhost + host: ~ # Port on the host. - port: 5672 + port: ~ # The user name to use. Note: Max 128 characters. - user: guest + user: ~ # Password. Note: Max 128 characters. - pass: guest + pass: ~ # The virtual host on the host. Note: Max 128 characters. - vhost: / + vhost: ~ # Connection timeout. Note: 0 or greater seconds. May be fractional. - connect_timeout: ~ + connection_timeout: ~ # Timeout in for income activity. Note: 0 or greater seconds. May be fractional. read_timeout: ~ # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. write_timeout: ~ - persisted: false - lazy: true + + # How often to send heartbeat. 0 means off. + heartbeat: ~ + persisted: ~ + lazy: ~ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher - receive_method: basic_get # One of "basic_get"; "basic_consume" + receive_method: ~ # One of "basic_get"; "basic_consume" + + # The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit" + qos_prefetch_size: ~ + + # Specifies a prefetch window in terms of whole messages + qos_prefetch_count: ~ + + # If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection. + qos_global: ~ + + # The options that are specific to the amqp transport you chose. For example amqp+lib have insist, keepalive, stream options. amqp+bunny has tcp_nodelay extra option. + driver_options: ~ # The delay strategy to be used. Possible values are "dlx", "delayed_message_plugin" or service id delay_strategy: dlx amqp_lib: - # The connection to AMQP broker set as a string. Other parameters are ignored if set + # The connection to AMQP broker set as a string. Other parameters could be used as defaults dsn: ~ # The host to connect too. Note: Max 1024 characters - host: localhost + host: ~ # Port on the host. - port: 5672 + port: ~ # The user name to use. Note: Max 128 characters. - user: guest + user: ~ # Password. Note: Max 128 characters. - pass: guest + pass: ~ # The virtual host on the host. Note: Max 128 characters. - vhost: / + vhost: ~ # Connection timeout. Note: 0 or greater seconds. May be fractional. - connection_timeout: !!float 3 - read_write_timeout: !!float 3 + connection_timeout: ~ # Timeout in for income activity. Note: 0 or greater seconds. May be fractional. - read_timeout: 3 + read_timeout: ~ # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. - write_timeout: 3 - lazy: true - stream: true - insist: false - keepalive: false + write_timeout: ~ + + # How often to send heartbeat. 0 means off. + heartbeat: ~ + persisted: ~ + lazy: ~ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher - receive_method: basic_get # One of "basic_get"; "basic_consume" - heartbeat: 0 + receive_method: ~ # One of "basic_get"; "basic_consume" + + # The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit" + qos_prefetch_size: ~ + + # Specifies a prefetch window in terms of whole messages + qos_prefetch_count: ~ + + # If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection. + qos_global: ~ + + # The options that are specific to the amqp transport you chose. For example amqp+lib have insist, keepalive, stream options. amqp+bunny has tcp_nodelay extra option. + driver_options: ~ rabbitmq_amqp_lib: - # The connection to AMQP broker set as a string. Other parameters are ignored if set + # The connection to AMQP broker set as a string. Other parameters could be used as defaults dsn: ~ # The host to connect too. Note: Max 1024 characters - host: localhost + host: ~ # Port on the host. - port: 5672 + port: ~ # The user name to use. Note: Max 128 characters. - user: guest + user: ~ # Password. Note: Max 128 characters. - pass: guest + pass: ~ # The virtual host on the host. Note: Max 128 characters. - vhost: / + vhost: ~ # Connection timeout. Note: 0 or greater seconds. May be fractional. - connection_timeout: !!float 3 - read_write_timeout: !!float 3 + connection_timeout: ~ # Timeout in for income activity. Note: 0 or greater seconds. May be fractional. - read_timeout: 3 + read_timeout: ~ # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. - write_timeout: 3 - lazy: true - stream: true - insist: false - keepalive: false + write_timeout: ~ + + # How often to send heartbeat. 0 means off. + heartbeat: ~ + persisted: ~ + lazy: ~ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher - receive_method: basic_get # One of "basic_get"; "basic_consume" - heartbeat: 0 + receive_method: ~ # One of "basic_get"; "basic_consume" + + # The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit" + qos_prefetch_size: ~ + + # Specifies a prefetch window in terms of whole messages + qos_prefetch_count: ~ + + # If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection. + qos_global: ~ + + # The options that are specific to the amqp transport you chose. For example amqp+lib have insist, keepalive, stream options. amqp+bunny has tcp_nodelay extra option. + driver_options: ~ # The delay strategy to be used. Possible values are "dlx", "delayed_message_plugin" or service id delay_strategy: dlx @@ -197,6 +249,9 @@ enqueue: # The queue files are created with this given permissions if not exist. chmod: 384 + + # How often query for new messages. + polling_interval: 100 redis: # can be a host, or the path to a unix domain socket @@ -240,52 +295,100 @@ enqueue: lazy: true amqp_bunny: - # The connection to AMQP broker set as a string. Other parameters are ignored if set + # The connection to AMQP broker set as a string. Other parameters could be used as defaults dsn: ~ # The host to connect too. Note: Max 1024 characters - host: localhost + host: ~ # Port on the host. - port: 5672 + port: ~ # The user name to use. Note: Max 128 characters. - user: guest + user: ~ # Password. Note: Max 128 characters. - pass: guest + pass: ~ # The virtual host on the host. Note: Max 128 characters. - vhost: / - lazy: true + vhost: ~ + + # Connection timeout. Note: 0 or greater seconds. May be fractional. + connection_timeout: ~ + + # Timeout in for income activity. Note: 0 or greater seconds. May be fractional. + read_timeout: ~ + + # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. + write_timeout: ~ + + # How often to send heartbeat. 0 means off. + heartbeat: ~ + persisted: ~ + lazy: ~ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher - receive_method: basic_get # One of "basic_get"; "basic_consume" - heartbeat: 0 + receive_method: ~ # One of "basic_get"; "basic_consume" + + # The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit" + qos_prefetch_size: ~ + + # Specifies a prefetch window in terms of whole messages + qos_prefetch_count: ~ + + # If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection. + qos_global: ~ + + # The options that are specific to the amqp transport you chose. For example amqp+lib have insist, keepalive, stream options. amqp+bunny has tcp_nodelay extra option. + driver_options: ~ rabbitmq_amqp_bunny: - # The connection to AMQP broker set as a string. Other parameters are ignored if set + # The connection to AMQP broker set as a string. Other parameters could be used as defaults dsn: ~ # The host to connect too. Note: Max 1024 characters - host: localhost + host: ~ # Port on the host. - port: 5672 + port: ~ # The user name to use. Note: Max 128 characters. - user: guest + user: ~ # Password. Note: Max 128 characters. - pass: guest + pass: ~ # The virtual host on the host. Note: Max 128 characters. - vhost: / - lazy: true + vhost: ~ + + # Connection timeout. Note: 0 or greater seconds. May be fractional. + connection_timeout: ~ + + # Timeout in for income activity. Note: 0 or greater seconds. May be fractional. + read_timeout: ~ + + # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. + write_timeout: ~ + + # How often to send heartbeat. 0 means off. + heartbeat: ~ + persisted: ~ + lazy: ~ # The receive strategy to be used. We suggest to use basic_consume as it is more performant. Though you need AMQP extension 1.9.1 or higher - receive_method: basic_get # One of "basic_get"; "basic_consume" - heartbeat: 0 + receive_method: ~ # One of "basic_get"; "basic_consume" + + # The server will send a message in advance if it is equal to or smaller in size than the available prefetch size. May be set to zero, meaning "no specific limit" + qos_prefetch_size: ~ + + # Specifies a prefetch window in terms of whole messages + qos_prefetch_count: ~ + + # If "false" the QoS settings apply to the current channel only. If this field is "true", they are applied to the entire connection. + qos_global: ~ + + # The options that are specific to the amqp transport you chose. For example amqp+lib have insist, keepalive, stream options. amqp+bunny has tcp_nodelay extra option. + driver_options: ~ # The delay strategy to be used. Possible values are "dlx", "delayed_message_plugin" or service id delay_strategy: dlx @@ -313,8 +416,6 @@ enqueue: doctrine_clear_identity_map_extension: false signal_extension: true reply_extension: true - - ``` [back to index](../index.md) From 5ac160285cea6b8e7ac087706b72617ebf5939a7 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Sat, 14 Oct 2017 20:15:08 +0300 Subject: [PATCH 6/6] [amqp-bunny] ignore broken pipe exception in __destruct() --- pkg/amqp-bunny/BunnyClient.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pkg/amqp-bunny/BunnyClient.php b/pkg/amqp-bunny/BunnyClient.php index fbaa0b396..8697b9de4 100644 --- a/pkg/amqp-bunny/BunnyClient.php +++ b/pkg/amqp-bunny/BunnyClient.php @@ -9,10 +9,12 @@ class BunnyClient extends Client { public function __destruct() { -// try { - parent::__destruct(); -// } catch (ClientException $e) { -// if ('' === $e->getMessage() -// } + try { + parent::__destruct(); + } catch (ClientException $e) { + if ('Broken pipe or closed connection.' !== $e->getMessage()) { + throw $e; + } + } } }