From f4fffbd90b462ec0e48afc1f4328f859952243f9 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 7 Jul 2017 15:40:15 +0300 Subject: [PATCH 01/76] Sync with cnages in queue interop. --- composer.json | 4 +-- pkg/amqp-ext/AmqpProducer.php | 43 +++++++++++++++++++++++++++ pkg/dbal/DbalProducer.php | 43 +++++++++++++++++++++++++++ pkg/fs/FsProducer.php | 43 +++++++++++++++++++++++++++ pkg/gearman/GearmanProducer.php | 43 +++++++++++++++++++++++++++ pkg/null/NullProducer.php | 43 +++++++++++++++++++++++++++ pkg/pheanstalk/PheanstalkProducer.php | 43 +++++++++++++++++++++++++++ pkg/redis/RedisProducer.php | 43 +++++++++++++++++++++++++++ pkg/sqs/SqsProducer.php | 43 +++++++++++++++++++++++++++ pkg/stomp/StompProducer.php | 43 +++++++++++++++++++++++++++ 10 files changed, 389 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 520ce055f..0472ed5c5 100644 --- a/composer.json +++ b/composer.json @@ -19,8 +19,8 @@ "enqueue/simple-client": "*@dev", "enqueue/test": "*@dev", "enqueue/async-event-dispatcher": "*@dev", - "queue-interop/queue-interop": "^0.5@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-interop": "dev-develop", + "queue-interop/queue-spec": "dev-develop", "phpunit/phpunit": "^5", "doctrine/doctrine-bundle": "~1.2", diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index 0ced3e6b2..9f0d44a6f 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -2,6 +2,7 @@ namespace Enqueue\AmqpExt; +use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -11,6 +12,16 @@ class AmqpProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * @var \AMQPChannel */ @@ -71,4 +82,36 @@ public function send(PsrDestination $destination, PsrMessage $message) ); } } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } diff --git a/pkg/dbal/DbalProducer.php b/pkg/dbal/DbalProducer.php index 8668a68ce..6a6c9d732 100644 --- a/pkg/dbal/DbalProducer.php +++ b/pkg/dbal/DbalProducer.php @@ -4,6 +4,7 @@ use Doctrine\DBAL\Types\Type; use Enqueue\Util\JSON; +use Interop\Queue\CompletionListener; use Interop\Queue\Exception; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; @@ -13,6 +14,16 @@ class DbalProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * @var DbalContext */ @@ -85,4 +96,36 @@ public function send(PsrDestination $destination, PsrMessage $message) throw new Exception('The transport fails to send the message due to some internal error.', null, $e); } } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } diff --git a/pkg/fs/FsProducer.php b/pkg/fs/FsProducer.php index a61584321..cd762683c 100644 --- a/pkg/fs/FsProducer.php +++ b/pkg/fs/FsProducer.php @@ -2,6 +2,7 @@ namespace Enqueue\Fs; +use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -11,6 +12,16 @@ class FsProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * @var FsContext */ @@ -56,4 +67,36 @@ public function send(PsrDestination $destination, PsrMessage $message) fwrite($file, $rawMessage); }); } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } diff --git a/pkg/gearman/GearmanProducer.php b/pkg/gearman/GearmanProducer.php index c7c072c76..12da0ea91 100644 --- a/pkg/gearman/GearmanProducer.php +++ b/pkg/gearman/GearmanProducer.php @@ -2,6 +2,7 @@ namespace Enqueue\Gearman; +use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -10,6 +11,16 @@ class GearmanProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * @var \GearmanClient */ @@ -41,4 +52,36 @@ public function send(PsrDestination $destination, PsrMessage $message) throw new \GearmanException(sprintf('The return code is not %s (GEARMAN_SUCCESS) but %s', \GEARMAN_SUCCESS, $code)); } } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } diff --git a/pkg/null/NullProducer.php b/pkg/null/NullProducer.php index 307d992e8..2523d82e4 100644 --- a/pkg/null/NullProducer.php +++ b/pkg/null/NullProducer.php @@ -2,16 +2,59 @@ namespace Enqueue\Null; +use Interop\Queue\CompletionListener; use Interop\Queue\PsrDestination; use Interop\Queue\PsrMessage; use Interop\Queue\PsrProducer; class NullProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * {@inheritdoc} */ public function send(PsrDestination $destination, PsrMessage $message) { } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } diff --git a/pkg/pheanstalk/PheanstalkProducer.php b/pkg/pheanstalk/PheanstalkProducer.php index 92ea44bec..93564b7a4 100644 --- a/pkg/pheanstalk/PheanstalkProducer.php +++ b/pkg/pheanstalk/PheanstalkProducer.php @@ -2,6 +2,7 @@ namespace Enqueue\Pheanstalk; +use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -11,6 +12,16 @@ class PheanstalkProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * @var Pheanstalk */ @@ -51,4 +62,36 @@ public function send(PsrDestination $destination, PsrMessage $message) $message->getTimeToRun() ); } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } diff --git a/pkg/redis/RedisProducer.php b/pkg/redis/RedisProducer.php index 55f65b1c2..e25dd2736 100644 --- a/pkg/redis/RedisProducer.php +++ b/pkg/redis/RedisProducer.php @@ -2,6 +2,7 @@ namespace Enqueue\Redis; +use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -10,6 +11,16 @@ class RedisProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * @var Redis */ @@ -36,4 +47,36 @@ public function send(PsrDestination $destination, PsrMessage $message) $this->redis->lpush($destination->getName(), json_encode($message)); } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index 0ea55340d..5252401c5 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -2,6 +2,7 @@ namespace Enqueue\Sqs; +use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -10,6 +11,16 @@ class SqsProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * @var SqsContext */ @@ -73,4 +84,36 @@ public function send(PsrDestination $destination, PsrMessage $message) throw new \RuntimeException('Message was not sent'); } } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } diff --git a/pkg/stomp/StompProducer.php b/pkg/stomp/StompProducer.php index 17bafbebe..cf5234f4a 100644 --- a/pkg/stomp/StompProducer.php +++ b/pkg/stomp/StompProducer.php @@ -2,6 +2,7 @@ namespace Enqueue\Stomp; +use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -12,6 +13,16 @@ class StompProducer implements PsrProducer { + /** + * @var CompletionListener + */ + private $completionListener; + + /** + * @var float + */ + private $deliveryDelay = PsrMessage::DEFAULT_DELIVERY_DELAY; + /** * @var Client */ @@ -44,4 +55,36 @@ public function send(PsrDestination $destination, PsrMessage $message) $this->stomp->send($destination->getQueueName(), $stompMessage); } + + /** + * {@inheritdoc} + */ + public function setCompletionListener(CompletionListener $listener = null) + { + $this->completionListener = $listener; + } + + /** + * @return CompletionListener|null + */ + public function getCompletionListener() + { + return $this->completionListener; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + } } From d48925fd2aab59cf41d5e74e61c11a4c0dc0c95b Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 7 Jul 2017 16:48:15 +0300 Subject: [PATCH 02/76] [sqs] Add support of delivery delayes, add specs --- pkg/sqs/SqsProducer.php | 1 + pkg/sqs/Tests/Spec/SqsProducerTest.php | 26 +++++++++++ ...dAndReceiveDelayedMessageFromQueueTest.php | 43 +++++++++++++++++++ .../Spec/SqsSendToAndReceiveFromQueueTest.php | 43 +++++++++++++++++++ .../Spec/SqsSendToAndReceiveFromTopicTest.php | 43 +++++++++++++++++++ ...SqsSendToAndReceiveNoWaitFromQueueTest.php | 24 +++++++++++ ...SqsSendToAndReceiveNoWaitFromTopicTest.php | 24 +++++++++++ .../SqsSendToTopicAndReceiveFromQueueTest.php | 24 +++++++++++ ...ndToTopicAndReceiveNoWaitFromQueueTest.php | 24 +++++++++++ 9 files changed, 252 insertions(+) create mode 100644 pkg/sqs/Tests/Spec/SqsProducerTest.php create mode 100644 pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php create mode 100644 pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromQueueTest.php create mode 100644 pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromTopicTest.php create mode 100644 pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromQueueTest.php create mode 100644 pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromTopicTest.php create mode 100644 pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveFromQueueTest.php create mode 100644 pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveNoWaitFromQueueTest.php diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index 5252401c5..22b94604a 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -64,6 +64,7 @@ public function send(PsrDestination $destination, PsrMessage $message) ], 'MessageBody' => $body, 'QueueUrl' => $this->context->getQueueUrl($destination), + 'DelaySeconds' => (int) $this->deliveryDelay / 1000, ]; if ($message->getDelaySeconds()) { diff --git a/pkg/sqs/Tests/Spec/SqsProducerTest.php b/pkg/sqs/Tests/Spec/SqsProducerTest.php new file mode 100644 index 000000000..cd61b9d2a --- /dev/null +++ b/pkg/sqs/Tests/Spec/SqsProducerTest.php @@ -0,0 +1,26 @@ + getenv('AWS__SQS__KEY'), + 'secret' => getenv('AWS__SQS__SECRET'), + 'region' => getenv('AWS__SQS__REGION'), + ]); + + return $factory->createContext()->createProducer(); + } +} diff --git a/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php new file mode 100644 index 000000000..7d7b30aae --- /dev/null +++ b/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php @@ -0,0 +1,43 @@ + getenv('AWS__SQS__KEY'), + 'secret' => getenv('AWS__SQS__SECRET'), + 'region' => getenv('AWS__SQS__REGION'), + ]); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + * + * @param SqsContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queueName = $queueName.time(); + + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + + return $queue; + } +} diff --git a/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromQueueTest.php new file mode 100644 index 000000000..3e73cd489 --- /dev/null +++ b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromQueueTest.php @@ -0,0 +1,43 @@ + getenv('AWS__SQS__KEY'), + 'secret' => getenv('AWS__SQS__SECRET'), + 'region' => getenv('AWS__SQS__REGION'), + ]); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + * + * @param SqsContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queueName = $queueName.time(); + + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + + return $queue; + } +} diff --git a/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromTopicTest.php b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromTopicTest.php new file mode 100644 index 000000000..5c4595e88 --- /dev/null +++ b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveFromTopicTest.php @@ -0,0 +1,43 @@ + getenv('AWS__SQS__KEY'), + 'secret' => getenv('AWS__SQS__SECRET'), + 'region' => getenv('AWS__SQS__REGION'), + ]); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + * + * @param SqsContext $context + */ + protected function createTopic(PsrContext $context, $topicName) + { + $topicName = $topicName.time(); + + $topic = $context->createTopic($topicName); + $context->declareQueue($topic); + + return $topic; + } +} diff --git a/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromQueueTest.php new file mode 100644 index 000000000..9301c647b --- /dev/null +++ b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromQueueTest.php @@ -0,0 +1,24 @@ +markTestSkipped('The test is fragile. This is how SQS.'); + } + + /** + * {@inheritdoc} + */ + protected function createContext() + { + throw new \LogicException('Should not be ever called'); + } +} diff --git a/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromTopicTest.php b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromTopicTest.php new file mode 100644 index 000000000..3d9149b05 --- /dev/null +++ b/pkg/sqs/Tests/Spec/SqsSendToAndReceiveNoWaitFromTopicTest.php @@ -0,0 +1,24 @@ +markTestSkipped('The test is fragile. This is how SQS.'); + } + + /** + * {@inheritdoc} + */ + protected function createContext() + { + throw new \LogicException('Should not be ever called'); + } +} diff --git a/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveFromQueueTest.php new file mode 100644 index 000000000..a9db45362 --- /dev/null +++ b/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveFromQueueTest.php @@ -0,0 +1,24 @@ +markTestSkipped('The SQS does not support it'); + } + + /** + * {@inheritdoc} + */ + protected function createContext() + { + throw new \LogicException('Should not be ever called'); + } +} diff --git a/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveNoWaitFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveNoWaitFromQueueTest.php new file mode 100644 index 000000000..bbb9be63a --- /dev/null +++ b/pkg/sqs/Tests/Spec/SqsSendToTopicAndReceiveNoWaitFromQueueTest.php @@ -0,0 +1,24 @@ +markTestSkipped('The SQS does not support it'); + } + + /** + * {@inheritdoc} + */ + protected function createContext() + { + throw new \LogicException('Should not be ever called'); + } +} From 030a3ad5ce794bbb7b8c98c1e0c70966d2bd8fd0 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 7 Jul 2017 16:48:31 +0300 Subject: [PATCH 03/76] [amqp] add producer spec. --- pkg/amqp-ext/Tests/Spec/AmqpProducerTest.php | 22 ++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 pkg/amqp-ext/Tests/Spec/AmqpProducerTest.php diff --git a/pkg/amqp-ext/Tests/Spec/AmqpProducerTest.php b/pkg/amqp-ext/Tests/Spec/AmqpProducerTest.php new file mode 100644 index 000000000..5c988c101 --- /dev/null +++ b/pkg/amqp-ext/Tests/Spec/AmqpProducerTest.php @@ -0,0 +1,22 @@ +createContext()->createProducer(); + } +} From 71f60cf87b99ef8373ca73f1fc4dff5aa71e31b7 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 7 Jul 2017 20:33:19 +0300 Subject: [PATCH 04/76] remove completion listnere feature for now. --- pkg/amqp-ext/AmqpProducer.php | 16 ---------------- pkg/dbal/DbalProducer.php | 16 ---------------- pkg/fs/FsProducer.php | 16 ---------------- pkg/gearman/GearmanProducer.php | 16 ---------------- pkg/null/NullProducer.php | 16 ---------------- pkg/pheanstalk/PheanstalkProducer.php | 16 ---------------- pkg/redis/RedisProducer.php | 16 ---------------- pkg/sqs/SqsProducer.php | 16 ---------------- pkg/stomp/StompProducer.php | 16 ---------------- 9 files changed, 144 deletions(-) diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index 9f0d44a6f..56cba2288 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -83,22 +83,6 @@ public function send(PsrDestination $destination, PsrMessage $message) } } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ diff --git a/pkg/dbal/DbalProducer.php b/pkg/dbal/DbalProducer.php index 6a6c9d732..6d69d866b 100644 --- a/pkg/dbal/DbalProducer.php +++ b/pkg/dbal/DbalProducer.php @@ -97,22 +97,6 @@ public function send(PsrDestination $destination, PsrMessage $message) } } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ diff --git a/pkg/fs/FsProducer.php b/pkg/fs/FsProducer.php index cd762683c..71d165051 100644 --- a/pkg/fs/FsProducer.php +++ b/pkg/fs/FsProducer.php @@ -68,22 +68,6 @@ public function send(PsrDestination $destination, PsrMessage $message) }); } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ diff --git a/pkg/gearman/GearmanProducer.php b/pkg/gearman/GearmanProducer.php index 12da0ea91..33ac267ff 100644 --- a/pkg/gearman/GearmanProducer.php +++ b/pkg/gearman/GearmanProducer.php @@ -53,22 +53,6 @@ public function send(PsrDestination $destination, PsrMessage $message) } } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ diff --git a/pkg/null/NullProducer.php b/pkg/null/NullProducer.php index 2523d82e4..2e747c700 100644 --- a/pkg/null/NullProducer.php +++ b/pkg/null/NullProducer.php @@ -26,22 +26,6 @@ public function send(PsrDestination $destination, PsrMessage $message) { } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ diff --git a/pkg/pheanstalk/PheanstalkProducer.php b/pkg/pheanstalk/PheanstalkProducer.php index 93564b7a4..70e81fd28 100644 --- a/pkg/pheanstalk/PheanstalkProducer.php +++ b/pkg/pheanstalk/PheanstalkProducer.php @@ -63,22 +63,6 @@ public function send(PsrDestination $destination, PsrMessage $message) ); } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ diff --git a/pkg/redis/RedisProducer.php b/pkg/redis/RedisProducer.php index e25dd2736..fdda58d03 100644 --- a/pkg/redis/RedisProducer.php +++ b/pkg/redis/RedisProducer.php @@ -48,22 +48,6 @@ public function send(PsrDestination $destination, PsrMessage $message) $this->redis->lpush($destination->getName(), json_encode($message)); } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index 22b94604a..bbe982964 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -86,22 +86,6 @@ public function send(PsrDestination $destination, PsrMessage $message) } } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ diff --git a/pkg/stomp/StompProducer.php b/pkg/stomp/StompProducer.php index cf5234f4a..d42aee549 100644 --- a/pkg/stomp/StompProducer.php +++ b/pkg/stomp/StompProducer.php @@ -56,22 +56,6 @@ public function send(PsrDestination $destination, PsrMessage $message) $this->stomp->send($destination->getQueueName(), $stompMessage); } - /** - * {@inheritdoc} - */ - public function setCompletionListener(CompletionListener $listener = null) - { - $this->completionListener = $listener; - } - - /** - * @return CompletionListener|null - */ - public function getCompletionListener() - { - return $this->completionListener; - } - /** * {@inheritdoc} */ From 968592ed193f86941fe2b5e20d0c7525bf2a26e5 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 7 Jul 2017 20:35:17 +0300 Subject: [PATCH 05/76] remove completion listnere feature for now. --- pkg/amqp-ext/AmqpProducer.php | 6 ------ pkg/dbal/DbalProducer.php | 6 ------ pkg/fs/FsProducer.php | 6 ------ pkg/gearman/GearmanProducer.php | 6 ------ pkg/null/NullProducer.php | 6 ------ pkg/pheanstalk/PheanstalkProducer.php | 6 ------ pkg/redis/RedisProducer.php | 6 ------ pkg/sqs/SqsProducer.php | 6 ------ pkg/stomp/StompProducer.php | 6 ------ 9 files changed, 54 deletions(-) diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index 56cba2288..b1abe1d66 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -2,7 +2,6 @@ namespace Enqueue\AmqpExt; -use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -12,11 +11,6 @@ class AmqpProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ diff --git a/pkg/dbal/DbalProducer.php b/pkg/dbal/DbalProducer.php index 6d69d866b..1d6ffb82f 100644 --- a/pkg/dbal/DbalProducer.php +++ b/pkg/dbal/DbalProducer.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\Types\Type; use Enqueue\Util\JSON; -use Interop\Queue\CompletionListener; use Interop\Queue\Exception; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; @@ -14,11 +13,6 @@ class DbalProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ diff --git a/pkg/fs/FsProducer.php b/pkg/fs/FsProducer.php index 71d165051..de995e205 100644 --- a/pkg/fs/FsProducer.php +++ b/pkg/fs/FsProducer.php @@ -2,7 +2,6 @@ namespace Enqueue\Fs; -use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -12,11 +11,6 @@ class FsProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ diff --git a/pkg/gearman/GearmanProducer.php b/pkg/gearman/GearmanProducer.php index 33ac267ff..ae47b41fc 100644 --- a/pkg/gearman/GearmanProducer.php +++ b/pkg/gearman/GearmanProducer.php @@ -2,7 +2,6 @@ namespace Enqueue\Gearman; -use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -11,11 +10,6 @@ class GearmanProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ diff --git a/pkg/null/NullProducer.php b/pkg/null/NullProducer.php index 2e747c700..24f938284 100644 --- a/pkg/null/NullProducer.php +++ b/pkg/null/NullProducer.php @@ -2,18 +2,12 @@ namespace Enqueue\Null; -use Interop\Queue\CompletionListener; use Interop\Queue\PsrDestination; use Interop\Queue\PsrMessage; use Interop\Queue\PsrProducer; class NullProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ diff --git a/pkg/pheanstalk/PheanstalkProducer.php b/pkg/pheanstalk/PheanstalkProducer.php index 70e81fd28..41944dbc2 100644 --- a/pkg/pheanstalk/PheanstalkProducer.php +++ b/pkg/pheanstalk/PheanstalkProducer.php @@ -2,7 +2,6 @@ namespace Enqueue\Pheanstalk; -use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -12,11 +11,6 @@ class PheanstalkProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ diff --git a/pkg/redis/RedisProducer.php b/pkg/redis/RedisProducer.php index fdda58d03..4b7e51d6c 100644 --- a/pkg/redis/RedisProducer.php +++ b/pkg/redis/RedisProducer.php @@ -2,7 +2,6 @@ namespace Enqueue\Redis; -use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -11,11 +10,6 @@ class RedisProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index bbe982964..e1916ed8b 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -2,7 +2,6 @@ namespace Enqueue\Sqs; -use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -11,11 +10,6 @@ class SqsProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ diff --git a/pkg/stomp/StompProducer.php b/pkg/stomp/StompProducer.php index d42aee549..95a8b639e 100644 --- a/pkg/stomp/StompProducer.php +++ b/pkg/stomp/StompProducer.php @@ -2,7 +2,6 @@ namespace Enqueue\Stomp; -use Interop\Queue\CompletionListener; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -13,11 +12,6 @@ class StompProducer implements PsrProducer { - /** - * @var CompletionListener - */ - private $completionListener; - /** * @var float */ From 09069a887b112ee4af67a4523038b3641344dbc4 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 21 Jul 2017 14:20:41 +0300 Subject: [PATCH 06/76] Update quick_tour.md --- docs/laravel/quick_tour.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/laravel/quick_tour.md b/docs/laravel/quick_tour.md index 72ac1ac02..84603c8f5 100644 --- a/docs/laravel/quick_tour.md +++ b/docs/laravel/quick_tour.md @@ -1,6 +1,10 @@ # Laravel Queue. Quick tour. -The [LaravelQueue](https://github.com/php-enqueue/laravel-queue) allows to use [queue-interop](https://github.com/queue-interop/queue-interop) compatible transports as [Laravel Queue](https://laravel.com/docs/5.4/queues). +You can use all transports built on top of [queue-interop](https://github.com/queue-interop/queue-interop) including [all supported](https://github.com/php-enqueue/enqueue-dev/tree/master/docs/transport) by Enqueue. + +The package allows you to use queue interop transport the [laravel way](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/laravel/queues.md) as well as integrates the [enqueue simple client](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/laravel/quick_tour.md#enqueue-simple-client). + +**NOTE:** The part of this code was originally proposed as a PR to [laravel/framework#20148](https://github.com/laravel/framework/pull/20148). It was closed without much explanations, so I decided to open source it as a stand alone package. ## Install From d503573029406c270a85340433769d85ea496bac Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 21 Jul 2017 14:45:10 +0300 Subject: [PATCH 07/76] add amqp-lib to relaese scripts. --- bin/release | 2 +- bin/subtree-split | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/release b/bin/release index 37f0c544c..a47c40aea 100755 --- a/bin/release +++ b/bin/release @@ -14,7 +14,7 @@ fi CURRENT_BRANCH=`git rev-parse --abbrev-ref HEAD` -for REMOTE in origin stomp amqp-ext pheanstalk gearman sqs fs redis dbal null rdkafka enqueue simple-client enqueue-bundle job-queue test async-event-dispatcher +for REMOTE in origin stomp amqp-ext amqp-lib pheanstalk gearman sqs fs redis dbal null rdkafka enqueue simple-client enqueue-bundle job-queue test async-event-dispatcher do echo "" echo "" diff --git a/bin/subtree-split b/bin/subtree-split index 3c0137bc8..d04e6f2aa 100755 --- a/bin/subtree-split +++ b/bin/subtree-split @@ -47,6 +47,7 @@ remote enqueue git@github.com:php-enqueue/enqueue.git remote simple-client git@github.com:php-enqueue/simple-client.git remote stomp git@github.com:php-enqueue/stomp.git remote amqp-ext git@github.com:php-enqueue/amqp-ext.git +remote amqp-lib git@github.com:php-enqueue/amqp-lib.git remote pheanstalk git@github.com:php-enqueue/pheanstalk.git remote gearman git@github.com:php-enqueue/gearman.git remote fs git@github.com:php-enqueue/fs.git @@ -64,6 +65,7 @@ split 'pkg/enqueue' enqueue split 'pkg/simple-client' simple-client split 'pkg/stomp' stomp split 'pkg/amqp-ext' amqp-ext +split 'pkg/amqp-lib' amqp-lib split 'pkg/pheanstalk' pheanstalk split 'pkg/gearman' gearman split 'pkg/rdkafka' rdkafka From 16476c8f7290d9e63514a1b2e86df763c4e6e6eb Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 24 Jul 2017 17:03:37 +0300 Subject: [PATCH 08/76] amqp interop --- composer.json | 10 + .../AmqpConnectionFactory.php | 196 +++++++++++ pkg/amqp-ext-interop/AmqpContext.php | 314 ++++++++++++++++++ pkg/amqp-ext-interop/Buffer.php | 43 +++ pkg/amqp-ext-interop/composer.json | 45 +++ 5 files changed, 608 insertions(+) create mode 100644 pkg/amqp-ext-interop/AmqpConnectionFactory.php create mode 100644 pkg/amqp-ext-interop/AmqpContext.php create mode 100644 pkg/amqp-ext-interop/Buffer.php create mode 100644 pkg/amqp-ext-interop/composer.json diff --git a/composer.json b/composer.json index 49c274e6d..15d33d92e 100644 --- a/composer.json +++ b/composer.json @@ -7,6 +7,8 @@ "enqueue/enqueue": "*@dev", "enqueue/stomp": "*@dev", "enqueue/amqp-ext": "*@dev", + "queue-interop/amqp-interop": "^0.5@dev", + "enqueue/amqp-ext-interop": "*@dev", "enqueue/amqp-lib": "*@dev", "php-amqplib/php-amqplib": "^2.7@dev", "enqueue/redis": "*@dev", @@ -121,6 +123,14 @@ { "type": "path", "url": "pkg/async-event-dispatcher" + }, + { + "type": "vcs", + "url": "git@github.com:queue-interop/amqp-interop.git" + }, + { + "type": "path", + "url": "pkg/amqp-ext-interop" } ] } diff --git a/pkg/amqp-ext-interop/AmqpConnectionFactory.php b/pkg/amqp-ext-interop/AmqpConnectionFactory.php new file mode 100644 index 000000000..0549d468e --- /dev/null +++ b/pkg/amqp-ext-interop/AmqpConnectionFactory.php @@ -0,0 +1,196 @@ + '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', + * 'pre_fetch_count' => 'Controls how many messages could be prefetched', + * 'pre_fetch_size' => 'Controls how many messages could be prefetched', + * '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 + */ + public function __construct($config = 'amqp://') + { + 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); + + $supportedMethods = ['basic_get', 'basic_consume']; + if (false == in_array($this->config['receive_method'], $supportedMethods, true)) { + throw new \LogicException(sprintf( + 'Invalid "receive_method" option value "%s". It could be only "%s"', + $this->config['receive_method'], + implode('", "', $supportedMethods) + )); + } + + if ('basic_consume' == $this->config['receive_method']) { + if (false == (version_compare(phpversion('amqp'), '1.9.1', '>=') || phpversion('amqp') == '1.9.1-dev')) { + // @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.'); + } + } + } + + /** + * {@inheritdoc} + * + * @return AmqpContext + */ + public function createContext() + { + if ($this->config['lazy']) { + return new AmqpContext(function () { + return $this->createExtContext($this->establishConnection()); + }, $this->config['receive_method']); + } + + return new AmqpContext($this->createExtContext($this->establishConnection()), $this->config['receive_method']); + } + + /** + * @param \AMQPConnection $extConnection + * + * @return \AMQPChannel + */ + private function createExtContext(\AMQPConnection $extConnection) + { + $channel = new \AMQPChannel($extConnection); + if (false == empty($this->config['pre_fetch_count'])) { + $channel->setPrefetchCount((int) $this->config['pre_fetch_count']); + } + + if (false == empty($this->config['pre_fetch_size'])) { + $channel->setPrefetchSize((int) $this->config['pre_fetch_size']); + } + + return $channel; + } + + /** + * @return \AMQPConnection + */ + 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(); + } + if (false == $this->connection->isConnected()) { + $this->config['persisted'] ? $this->connection->preconnect() : $this->connection->reconnect(); + } + + return $this->connection; + } + + /** + * @param string $dsn + * + * @return array + */ + private function parseDsn($dsn) + { + $dsnConfig = parse_url(https://github.com/$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); + + 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, + 'pre_fetch_count' => null, + 'pre_fetch_size' => null, + 'receive_method' => 'basic_get', + ]; + } +} diff --git a/pkg/amqp-ext-interop/AmqpContext.php b/pkg/amqp-ext-interop/AmqpContext.php new file mode 100644 index 000000000..0eda933bd --- /dev/null +++ b/pkg/amqp-ext-interop/AmqpContext.php @@ -0,0 +1,314 @@ +receiveMethod = $receiveMethod; + + if ($extChannel instanceof \AMQPChannel) { + $this->extChannel = $extChannel; + } elseif (is_callable($extChannel)) { + $this->extChannelFactory = $extChannel; + } else { + throw new \InvalidArgumentException('The extChannel argument must be either AMQPChannel or callable that return AMQPChannel.'); + } + + $this->buffer = new Buffer(); + } + + /** + * {@inheritdoc} + */ + public function createMessage($body = '', array $properties = [], array $headers = []) + { + return new AmqpMessage($body, $properties, $headers); + } + + /** + * {@inheritdoc} + */ + public function createTopic($topicName) + { + return new AmqpTopic($topicName); + } + + /** + * {@inheritdoc} + */ + public function deleteTopic(InteropAmqpTopic $topic) + { + $extExchange = new \AMQPExchange($this->getExtChannel()); + $extExchange->delete($topic->getTopicName(), $this->convertTopicFlags($topic->getFlags())); + } + + /** + * {@inheritdoc} + */ + public function declareTopic(InteropAmqpTopic $topic) + { + $extExchange = new \AMQPExchange($this->getExtChannel()); + $extExchange->setName($topic->getTopicName()); + $extExchange->setType($topic->getType()); + $extExchange->setArguments($topic->getArguments()); + $extExchange->setFlags($this->convertTopicFlags($topic->getFlags())); + + $extExchange->declareExchange(); + } + + /** + * {@inheritdoc} + */ + public function createQueue($queueName) + { + return new AmqpQueue($queueName); + } + + /** + * {@inheritdoc} + */ + public function deleteQueue(InteropAmqpQueue $queue) + { + $extQueue = new \AMQPQueue($this->getExtChannel()); + $extQueue->setName($queue->getQueueName()); + $extQueue->delete($this->convertQueueFlags($queue->getFlags())); + } + + /** + * {@inheritdoc} + */ + public function declareQueue(InteropAmqpQueue $queue) + { + $extQueue = new \AMQPQueue($this->getExtChannel()); + $extQueue->setName($queue->getQueueName()); + $extQueue->setArguments($queue->getArguments()); + $extQueue->setFlags($this->convertQueueFlags($queue->getFlags())); + + return $extQueue->declareQueue(); + } + + /** + * {@inheritdoc} + */ + public function purgeQueue(InteropAmqpQueue $queue) + { + $amqpQueue = new \AMQPQueue($this->getExtChannel()); + $amqpQueue->setName($queue->getQueueName()); + $amqpQueue->purge(); + } + + /** + * {@inheritdoc} + */ + public function bind(InteropAmqpBind $bind) + { + if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { + throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic'); + } + + // bind exchange to exchange + if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { + $exchange = new \AMQPExchange($this->getExtChannel()); + $exchange->setName($bind->getSource()->getTopicName()); + $exchange->bind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + // bind queue to exchange + } elseif ($bind->getSource() instanceof InteropAmqpQueue) { + $queue = new \AMQPQueue($this->getExtChannel()); + $queue->setName($bind->getSource()->getQueueName()); + $queue->bind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + // bind exchange to queue + } else { + $queue = new \AMQPQueue($this->getExtChannel()); + $queue->setName($bind->getTarget()->getQueueName()); + $queue->bind($bind->getSource()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + } + } + + /** + * {@inheritdoc} + */ + public function unbind(InteropAmqpBind $bind) + { + if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { + throw new Exception('Is not possible to unbind queue to queue. It is possible to unbind topic from queue or topic from topic'); + } + + // unbind exchange from exchange + if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { + $exchange = new \AMQPExchange($this->getExtChannel()); + $exchange->setName($bind->getSource()->getTopicName()); + $exchange->unbind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + // unbind queue from exchange + } elseif ($bind->getSource() instanceof InteropAmqpQueue) { + $queue = new \AMQPQueue($this->getExtChannel()); + $queue->setName($bind->getSource()->getQueueName()); + $queue->unbind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + // unbind exchange from queue + } else { + $queue = new \AMQPQueue($this->getExtChannel()); + $queue->setName($bind->getTarget()->getQueueName()); + $queue->unbind($bind->getSource()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + } + } + + /** + * {@inheritdoc} + * + * @return InteropAmqpQueue + */ + public function createTemporaryQueue() + { + $extQueue = new \AMQPQueue($this->getExtChannel()); + $extQueue->setFlags(AMQP_EXCLUSIVE); + + $extQueue->declareQueue(); + + $queue = $this->createQueue($extQueue->getName()); + $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE); + + return $queue; + } + + /** + * @return \AMQPChannel + */ + public function getExtChannel() + { + if (false == $this->extChannel) { + $extChannel = call_user_func($this->extChannelFactory); + if (false == $extChannel instanceof \AMQPChannel) { + throw new \LogicException(sprintf( + 'The factory must return instance of AMQPChannel. It returns %s', + is_object($extChannel) ? get_class($extChannel) : gettype($extChannel) + )); + } + + $this->extChannel = $extChannel; + } + + return $this->extChannel; + } + + /** + * @param int $interop + * + * @return int + */ + private function convertMessageFlags($interop) + { + $flags = AMQP_NOPARAM; + + if ($interop & InteropAmqpMessage::FLAG_MANDATORY) { + $flags |= AMQP_MANDATORY; + } + + if ($interop & InteropAmqpMessage::FLAG_IMMEDIATE) { + $flags |= AMQP_IMMEDIATE; + } + + return $flags; + } + + /** + * @param int $interop + * + * @return int + */ + private function convertTopicFlags($interop) + { + $flags = AMQP_NOPARAM; + + $flags |= $this->convertDestinationFlags($interop); + + if ($interop & InteropAmqpTopic::FLAG_INTERNAL) { + $flags |= AMQP_INTERNAL; + } + + return $flags; + } + + /** + * @param int $interop + * + * @return int + */ + private function convertQueueFlags($interop) + { + $flags = AMQP_NOPARAM; + + $flags |= $this->convertDestinationFlags($interop); + + if ($interop & InteropAmqpQueue::FLAG_EXCLUSIVE) { + $flags |= AMQP_EXCLUSIVE; + } + + return $flags; + } + + /** + * @param int $interop + * + * @return int + */ + private function convertDestinationFlags($interop) + { + $flags = AMQP_NOPARAM; + + if ($interop & InteropAmqpDestination::FLAG_PASSIVE) { + $flags |= AMQP_PASSIVE; + } + + if ($interop & InteropAmqpDestination::FLAG_DURABLE) { + $flags |= AMQP_DURABLE; + } + + if ($interop & InteropAmqpDestination::FLAG_AUTODELETE) { + $flags |= AMQP_AUTODELETE; + } + + if ($interop & InteropAmqpDestination::FLAG_NOWAIT) { + $flags |= AMQP_NOWAIT; + } + + return $flags; + } +} diff --git a/pkg/amqp-ext-interop/Buffer.php b/pkg/amqp-ext-interop/Buffer.php new file mode 100644 index 000000000..3c425b700 --- /dev/null +++ b/pkg/amqp-ext-interop/Buffer.php @@ -0,0 +1,43 @@ + [AmqpMessage, AmqpMessage ...]] + */ + private $messages; + + public function __construct() + { + $this->messages = []; + } + + /** + * @param string $consumerTag + * @param AmqpMessage $message + */ + public function push($consumerTag, AmqpMessage $message) + { + if (false == array_key_exists($consumerTag, $this->messages)) { + $this->messages[$consumerTag] = []; + } + + $this->messages[$consumerTag][] = $message; + } + + /** + * @param string $consumerTag + * + * @return AmqpMessage|null + */ + public function pop($consumerTag) + { + if (false == empty($this->messages[$consumerTag])) { + return array_shift($this->messages[$consumerTag]); + } + } +} diff --git a/pkg/amqp-ext-interop/composer.json b/pkg/amqp-ext-interop/composer.json new file mode 100644 index 000000000..dd815f0e3 --- /dev/null +++ b/pkg/amqp-ext-interop/composer.json @@ -0,0 +1,45 @@ +{ + "name": "enqueue/amqp-ext-interop", + "type": "library", + "description": "Message Queue Amqp Transport", + "keywords": ["messaging", "queue", "amqp"], + "license": "MIT", + "repositories": [ + { + "type": "vcs", + "url": "git@github.com:php-enqueue/test.git" + } + ], + "require": { + "php": ">=5.6", + "ext-amqp": "^1.6", + "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/amqp-interop": "^0.5@dev", + "psr/log": "^1" + }, + "require-dev": { + "phpunit/phpunit": "~5.4.0", + "enqueue/test": "^0.6@dev", + "enqueue/enqueue": "^0.6@dev", + "enqueue/null": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", + "empi89/php-amqp-stubs": "*@dev", + "symfony/dependency-injection": "^2.8|^3", + "symfony/config": "^2.8|^3" + }, + "autoload": { + "psr-4": { "Enqueue\\AmqpExtInterop\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "suggest": { + "enqueue/enqueue": "If you'd like to use advanced features like Client abstract layer or Symfony integration features" + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "0.6.x-dev" + } + } +} From 1dc968b73e95d09aa1539d6d66c451a342d893b6 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Tue, 25 Jul 2017 14:34:59 +0300 Subject: [PATCH 09/76] amqp ext interop --- composer.json | 7 +- .../AmqpConnectionFactory.php | 196 ----------- pkg/amqp-ext-interop/AmqpContext.php | 314 ------------------ pkg/amqp-ext-interop/Buffer.php | 43 --- pkg/amqp-ext-interop/composer.json | 45 --- pkg/amqp-ext/AmqpConnectionFactory.php | 4 +- pkg/amqp-ext/AmqpConsumer.php | 82 ++++- pkg/amqp-ext/AmqpContext.php | 186 ++++++----- pkg/amqp-ext/AmqpMessage.php | 273 --------------- pkg/amqp-ext/AmqpProducer.php | 15 +- pkg/amqp-ext/AmqpQueue.php | 130 -------- pkg/amqp-ext/AmqpTopic.php | 130 -------- pkg/amqp-ext/Buffer.php | 2 + pkg/amqp-ext/Flags.php | 124 +++++++ pkg/amqp-ext/composer.json | 1 + pkg/amqp-ext/examples/consume.php | 3 - pkg/amqp-ext/examples/produce.php | 15 +- 17 files changed, 321 insertions(+), 1249 deletions(-) delete mode 100644 pkg/amqp-ext-interop/AmqpConnectionFactory.php delete mode 100644 pkg/amqp-ext-interop/AmqpContext.php delete mode 100644 pkg/amqp-ext-interop/Buffer.php delete mode 100644 pkg/amqp-ext-interop/composer.json delete mode 100644 pkg/amqp-ext/AmqpMessage.php delete mode 100644 pkg/amqp-ext/AmqpQueue.php delete mode 100644 pkg/amqp-ext/AmqpTopic.php create mode 100644 pkg/amqp-ext/Flags.php diff --git a/composer.json b/composer.json index 15d33d92e..235c4fa53 100644 --- a/composer.json +++ b/composer.json @@ -7,8 +7,6 @@ "enqueue/enqueue": "*@dev", "enqueue/stomp": "*@dev", "enqueue/amqp-ext": "*@dev", - "queue-interop/amqp-interop": "^0.5@dev", - "enqueue/amqp-ext-interop": "*@dev", "enqueue/amqp-lib": "*@dev", "php-amqplib/php-amqplib": "^2.7@dev", "enqueue/redis": "*@dev", @@ -27,6 +25,7 @@ "enqueue/async-event-dispatcher": "*@dev", "queue-interop/queue-interop": "^0.5@dev", "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/amqp-interop": "^0.5@dev", "phpunit/phpunit": "^5", "doctrine/doctrine-bundle": "~1.2", @@ -127,10 +126,6 @@ { "type": "vcs", "url": "git@github.com:queue-interop/amqp-interop.git" - }, - { - "type": "path", - "url": "pkg/amqp-ext-interop" } ] } diff --git a/pkg/amqp-ext-interop/AmqpConnectionFactory.php b/pkg/amqp-ext-interop/AmqpConnectionFactory.php deleted file mode 100644 index 0549d468e..000000000 --- a/pkg/amqp-ext-interop/AmqpConnectionFactory.php +++ /dev/null @@ -1,196 +0,0 @@ - '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', - * 'pre_fetch_count' => 'Controls how many messages could be prefetched', - * 'pre_fetch_size' => 'Controls how many messages could be prefetched', - * '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 - */ - public function __construct($config = 'amqp://') - { - 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); - - $supportedMethods = ['basic_get', 'basic_consume']; - if (false == in_array($this->config['receive_method'], $supportedMethods, true)) { - throw new \LogicException(sprintf( - 'Invalid "receive_method" option value "%s". It could be only "%s"', - $this->config['receive_method'], - implode('", "', $supportedMethods) - )); - } - - if ('basic_consume' == $this->config['receive_method']) { - if (false == (version_compare(phpversion('amqp'), '1.9.1', '>=') || phpversion('amqp') == '1.9.1-dev')) { - // @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.'); - } - } - } - - /** - * {@inheritdoc} - * - * @return AmqpContext - */ - public function createContext() - { - if ($this->config['lazy']) { - return new AmqpContext(function () { - return $this->createExtContext($this->establishConnection()); - }, $this->config['receive_method']); - } - - return new AmqpContext($this->createExtContext($this->establishConnection()), $this->config['receive_method']); - } - - /** - * @param \AMQPConnection $extConnection - * - * @return \AMQPChannel - */ - private function createExtContext(\AMQPConnection $extConnection) - { - $channel = new \AMQPChannel($extConnection); - if (false == empty($this->config['pre_fetch_count'])) { - $channel->setPrefetchCount((int) $this->config['pre_fetch_count']); - } - - if (false == empty($this->config['pre_fetch_size'])) { - $channel->setPrefetchSize((int) $this->config['pre_fetch_size']); - } - - return $channel; - } - - /** - * @return \AMQPConnection - */ - 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(); - } - if (false == $this->connection->isConnected()) { - $this->config['persisted'] ? $this->connection->preconnect() : $this->connection->reconnect(); - } - - return $this->connection; - } - - /** - * @param string $dsn - * - * @return array - */ - private function parseDsn($dsn) - { - $dsnConfig = parse_url(https://github.com/$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); - - 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, - 'pre_fetch_count' => null, - 'pre_fetch_size' => null, - 'receive_method' => 'basic_get', - ]; - } -} diff --git a/pkg/amqp-ext-interop/AmqpContext.php b/pkg/amqp-ext-interop/AmqpContext.php deleted file mode 100644 index 0eda933bd..000000000 --- a/pkg/amqp-ext-interop/AmqpContext.php +++ /dev/null @@ -1,314 +0,0 @@ -receiveMethod = $receiveMethod; - - if ($extChannel instanceof \AMQPChannel) { - $this->extChannel = $extChannel; - } elseif (is_callable($extChannel)) { - $this->extChannelFactory = $extChannel; - } else { - throw new \InvalidArgumentException('The extChannel argument must be either AMQPChannel or callable that return AMQPChannel.'); - } - - $this->buffer = new Buffer(); - } - - /** - * {@inheritdoc} - */ - public function createMessage($body = '', array $properties = [], array $headers = []) - { - return new AmqpMessage($body, $properties, $headers); - } - - /** - * {@inheritdoc} - */ - public function createTopic($topicName) - { - return new AmqpTopic($topicName); - } - - /** - * {@inheritdoc} - */ - public function deleteTopic(InteropAmqpTopic $topic) - { - $extExchange = new \AMQPExchange($this->getExtChannel()); - $extExchange->delete($topic->getTopicName(), $this->convertTopicFlags($topic->getFlags())); - } - - /** - * {@inheritdoc} - */ - public function declareTopic(InteropAmqpTopic $topic) - { - $extExchange = new \AMQPExchange($this->getExtChannel()); - $extExchange->setName($topic->getTopicName()); - $extExchange->setType($topic->getType()); - $extExchange->setArguments($topic->getArguments()); - $extExchange->setFlags($this->convertTopicFlags($topic->getFlags())); - - $extExchange->declareExchange(); - } - - /** - * {@inheritdoc} - */ - public function createQueue($queueName) - { - return new AmqpQueue($queueName); - } - - /** - * {@inheritdoc} - */ - public function deleteQueue(InteropAmqpQueue $queue) - { - $extQueue = new \AMQPQueue($this->getExtChannel()); - $extQueue->setName($queue->getQueueName()); - $extQueue->delete($this->convertQueueFlags($queue->getFlags())); - } - - /** - * {@inheritdoc} - */ - public function declareQueue(InteropAmqpQueue $queue) - { - $extQueue = new \AMQPQueue($this->getExtChannel()); - $extQueue->setName($queue->getQueueName()); - $extQueue->setArguments($queue->getArguments()); - $extQueue->setFlags($this->convertQueueFlags($queue->getFlags())); - - return $extQueue->declareQueue(); - } - - /** - * {@inheritdoc} - */ - public function purgeQueue(InteropAmqpQueue $queue) - { - $amqpQueue = new \AMQPQueue($this->getExtChannel()); - $amqpQueue->setName($queue->getQueueName()); - $amqpQueue->purge(); - } - - /** - * {@inheritdoc} - */ - public function bind(InteropAmqpBind $bind) - { - if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { - throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic'); - } - - // bind exchange to exchange - if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { - $exchange = new \AMQPExchange($this->getExtChannel()); - $exchange->setName($bind->getSource()->getTopicName()); - $exchange->bind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); - // bind queue to exchange - } elseif ($bind->getSource() instanceof InteropAmqpQueue) { - $queue = new \AMQPQueue($this->getExtChannel()); - $queue->setName($bind->getSource()->getQueueName()); - $queue->bind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); - // bind exchange to queue - } else { - $queue = new \AMQPQueue($this->getExtChannel()); - $queue->setName($bind->getTarget()->getQueueName()); - $queue->bind($bind->getSource()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); - } - } - - /** - * {@inheritdoc} - */ - public function unbind(InteropAmqpBind $bind) - { - if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { - throw new Exception('Is not possible to unbind queue to queue. It is possible to unbind topic from queue or topic from topic'); - } - - // unbind exchange from exchange - if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { - $exchange = new \AMQPExchange($this->getExtChannel()); - $exchange->setName($bind->getSource()->getTopicName()); - $exchange->unbind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); - // unbind queue from exchange - } elseif ($bind->getSource() instanceof InteropAmqpQueue) { - $queue = new \AMQPQueue($this->getExtChannel()); - $queue->setName($bind->getSource()->getQueueName()); - $queue->unbind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); - // unbind exchange from queue - } else { - $queue = new \AMQPQueue($this->getExtChannel()); - $queue->setName($bind->getTarget()->getQueueName()); - $queue->unbind($bind->getSource()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); - } - } - - /** - * {@inheritdoc} - * - * @return InteropAmqpQueue - */ - public function createTemporaryQueue() - { - $extQueue = new \AMQPQueue($this->getExtChannel()); - $extQueue->setFlags(AMQP_EXCLUSIVE); - - $extQueue->declareQueue(); - - $queue = $this->createQueue($extQueue->getName()); - $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE); - - return $queue; - } - - /** - * @return \AMQPChannel - */ - public function getExtChannel() - { - if (false == $this->extChannel) { - $extChannel = call_user_func($this->extChannelFactory); - if (false == $extChannel instanceof \AMQPChannel) { - throw new \LogicException(sprintf( - 'The factory must return instance of AMQPChannel. It returns %s', - is_object($extChannel) ? get_class($extChannel) : gettype($extChannel) - )); - } - - $this->extChannel = $extChannel; - } - - return $this->extChannel; - } - - /** - * @param int $interop - * - * @return int - */ - private function convertMessageFlags($interop) - { - $flags = AMQP_NOPARAM; - - if ($interop & InteropAmqpMessage::FLAG_MANDATORY) { - $flags |= AMQP_MANDATORY; - } - - if ($interop & InteropAmqpMessage::FLAG_IMMEDIATE) { - $flags |= AMQP_IMMEDIATE; - } - - return $flags; - } - - /** - * @param int $interop - * - * @return int - */ - private function convertTopicFlags($interop) - { - $flags = AMQP_NOPARAM; - - $flags |= $this->convertDestinationFlags($interop); - - if ($interop & InteropAmqpTopic::FLAG_INTERNAL) { - $flags |= AMQP_INTERNAL; - } - - return $flags; - } - - /** - * @param int $interop - * - * @return int - */ - private function convertQueueFlags($interop) - { - $flags = AMQP_NOPARAM; - - $flags |= $this->convertDestinationFlags($interop); - - if ($interop & InteropAmqpQueue::FLAG_EXCLUSIVE) { - $flags |= AMQP_EXCLUSIVE; - } - - return $flags; - } - - /** - * @param int $interop - * - * @return int - */ - private function convertDestinationFlags($interop) - { - $flags = AMQP_NOPARAM; - - if ($interop & InteropAmqpDestination::FLAG_PASSIVE) { - $flags |= AMQP_PASSIVE; - } - - if ($interop & InteropAmqpDestination::FLAG_DURABLE) { - $flags |= AMQP_DURABLE; - } - - if ($interop & InteropAmqpDestination::FLAG_AUTODELETE) { - $flags |= AMQP_AUTODELETE; - } - - if ($interop & InteropAmqpDestination::FLAG_NOWAIT) { - $flags |= AMQP_NOWAIT; - } - - return $flags; - } -} diff --git a/pkg/amqp-ext-interop/Buffer.php b/pkg/amqp-ext-interop/Buffer.php deleted file mode 100644 index 3c425b700..000000000 --- a/pkg/amqp-ext-interop/Buffer.php +++ /dev/null @@ -1,43 +0,0 @@ - [AmqpMessage, AmqpMessage ...]] - */ - private $messages; - - public function __construct() - { - $this->messages = []; - } - - /** - * @param string $consumerTag - * @param AmqpMessage $message - */ - public function push($consumerTag, AmqpMessage $message) - { - if (false == array_key_exists($consumerTag, $this->messages)) { - $this->messages[$consumerTag] = []; - } - - $this->messages[$consumerTag][] = $message; - } - - /** - * @param string $consumerTag - * - * @return AmqpMessage|null - */ - public function pop($consumerTag) - { - if (false == empty($this->messages[$consumerTag])) { - return array_shift($this->messages[$consumerTag]); - } - } -} diff --git a/pkg/amqp-ext-interop/composer.json b/pkg/amqp-ext-interop/composer.json deleted file mode 100644 index dd815f0e3..000000000 --- a/pkg/amqp-ext-interop/composer.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "enqueue/amqp-ext-interop", - "type": "library", - "description": "Message Queue Amqp Transport", - "keywords": ["messaging", "queue", "amqp"], - "license": "MIT", - "repositories": [ - { - "type": "vcs", - "url": "git@github.com:php-enqueue/test.git" - } - ], - "require": { - "php": ">=5.6", - "ext-amqp": "^1.6", - "queue-interop/queue-interop": "^0.5@dev", - "queue-interop/amqp-interop": "^0.5@dev", - "psr/log": "^1" - }, - "require-dev": { - "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", - "queue-interop/queue-spec": "^0.5@dev", - "empi89/php-amqp-stubs": "*@dev", - "symfony/dependency-injection": "^2.8|^3", - "symfony/config": "^2.8|^3" - }, - "autoload": { - "psr-4": { "Enqueue\\AmqpExtInterop\\": "" }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "suggest": { - "enqueue/enqueue": "If you'd like to use advanced features like Client abstract layer or Symfony integration features" - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-master": "0.6.x-dev" - } - } -} diff --git a/pkg/amqp-ext/AmqpConnectionFactory.php b/pkg/amqp-ext/AmqpConnectionFactory.php index 15e1d6841..537cb94c5 100644 --- a/pkg/amqp-ext/AmqpConnectionFactory.php +++ b/pkg/amqp-ext/AmqpConnectionFactory.php @@ -2,9 +2,9 @@ namespace Enqueue\AmqpExt; -use Interop\Queue\PsrConnectionFactory; +use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory; -class AmqpConnectionFactory implements PsrConnectionFactory +class AmqpConnectionFactory implements InteropAmqpConnectionFactory { /** * @var array diff --git a/pkg/amqp-ext/AmqpConsumer.php b/pkg/amqp-ext/AmqpConsumer.php index 5834232e4..68d7a3dc9 100644 --- a/pkg/amqp-ext/AmqpConsumer.php +++ b/pkg/amqp-ext/AmqpConsumer.php @@ -2,11 +2,14 @@ namespace Enqueue\AmqpExt; +use Interop\Amqp\AmqpConsumer as InteropAmqpConsumer; +use Interop\Amqp\AmqpMessage as InteropAmqpMessage; +use Interop\Amqp\AmqpQueue; +use Interop\Amqp\Impl\AmqpMessage; use Interop\Queue\InvalidMessageException; -use Interop\Queue\PsrConsumer; use Interop\Queue\PsrMessage; -class AmqpConsumer implements PsrConsumer +class AmqpConsumer implements InteropAmqpConsumer { /** * @var AmqpContext @@ -38,6 +41,16 @@ class AmqpConsumer implements PsrConsumer */ private $receiveMethod; + /** + * @var int + */ + private $flags; + + /** + * @var string + */ + private $consumerTag; + /** * @param AmqpContext $context * @param AmqpQueue $queue @@ -50,10 +63,59 @@ public function __construct(AmqpContext $context, AmqpQueue $queue, Buffer $buff $this->context = $context; $this->buffer = $buffer; $this->receiveMethod = $receiveMethod; + $this->flags = self::FLAG_NOPARAM; $this->isInit = false; } + /** + * {@inheritdoc} + */ + public function setConsumerTag($consumerTag) + { + $this->consumerTag = $consumerTag; + } + + /** + * {@inheritdoc} + */ + public function getConsumerTag() + { + return $this->consumerTag; + } + + /** + * {@inheritdoc} + */ + public function clearFlags() + { + $this->flags = self::FLAG_NOPARAM; + } + + /** + * {@inheritdoc} + */ + public function addFlag($flag) + { + $this->flags |= $flag; + } + + /** + * {@inheritdoc} + */ + public function getFlags() + { + return $this->flags; + } + + /** + * {@inheritdoc} + */ + public function setFlags($flags) + { + $this->flags = $flags; + } + /** * {@inheritdoc} * @@ -67,7 +129,7 @@ public function getQueue() /** * {@inheritdoc} * - * @return AmqpMessage|null + * @return InteropAmqpMessage|null */ public function receive($timeout = 0) { @@ -89,7 +151,7 @@ public function receive($timeout = 0) */ public function receiveNoWait() { - if ($extMessage = $this->getExtQueue()->get()) { + if ($extMessage = $this->getExtQueue()->get(Flags::convertConsumerFlags($this->flags))) { return $this->convertMessage($extMessage); } } @@ -101,7 +163,7 @@ public function receiveNoWait() */ public function acknowledge(PsrMessage $message) { - InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class); + InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); $this->getExtQueue()->ack($message->getDeliveryTag()); } @@ -113,7 +175,7 @@ public function acknowledge(PsrMessage $message) */ public function reject(PsrMessage $message, $requeue = false) { - InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class); + InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); $this->getExtQueue()->reject( $message->getDeliveryTag(), @@ -124,7 +186,7 @@ public function reject(PsrMessage $message, $requeue = false) /** * @param int $timeout * - * @return AmqpMessage|null + * @return InteropAmqpMessage|null */ private function receiveBasicGet($timeout) { @@ -142,7 +204,7 @@ private function receiveBasicGet($timeout) /** * @param int $timeout * - * @return AmqpMessage|null + * @return InteropAmqpMessage|null */ private function receiveBasicConsume($timeout) { @@ -158,7 +220,7 @@ private function receiveBasicConsume($timeout) $extConnection->setReadTimeout($timeout / 1000); if (false == $this->isInit) { - $this->getExtQueue()->consume(null, AMQP_NOPARAM); + $this->getExtQueue()->consume(null, Flags::convertConsumerFlags($this->flags), $this->consumerTag); $this->isInit = true; } @@ -232,7 +294,7 @@ private function getExtQueue() if (false == $this->extQueue) { $extQueue = new \AMQPQueue($this->context->getExtChannel()); $extQueue->setName($this->queue->getQueueName()); - $extQueue->setFlags($this->queue->getFlags()); + $extQueue->setFlags(Flags::convertQueueFlags($this->queue->getFlags())); $extQueue->setArguments($this->queue->getArguments()); $this->extQueue = $extQueue; diff --git a/pkg/amqp-ext/AmqpContext.php b/pkg/amqp-ext/AmqpContext.php index 70f18512e..76a4974ee 100644 --- a/pkg/amqp-ext/AmqpContext.php +++ b/pkg/amqp-ext/AmqpContext.php @@ -2,13 +2,20 @@ namespace Enqueue\AmqpExt; +use Enqueue\Psr\Exception; +use Interop\Amqp\AmqpContext as InteropAmqpContext; +use Interop\Amqp\AmqpTopic as InteropAmqpTopic; +use Interop\Amqp\AmqpQueue as InteropAmqpQueue; +use Interop\Amqp\AmqpBind as InteropAmqpBind; +use Interop\Amqp\Impl\AmqpBind; +use Interop\Amqp\Impl\AmqpMessage; +use Interop\Amqp\Impl\AmqpQueue; +use Interop\Amqp\Impl\AmqpTopic; use Interop\Queue\InvalidDestinationException; -use Interop\Queue\PsrContext; use Interop\Queue\PsrDestination; -use Interop\Queue\PsrQueue; use Interop\Queue\PsrTopic; -class AmqpContext implements PsrContext +class AmqpContext implements InteropAmqpContext { /** * @var \AMQPChannel @@ -53,8 +60,6 @@ public function __construct($extChannel, $receiveMethod) /** * {@inheritdoc} - * - * @return AmqpMessage */ public function createMessage($body = '', array $properties = [], array $headers = []) { @@ -63,8 +68,6 @@ public function createMessage($body = '', array $properties = [], array $headers /** * {@inheritdoc} - * - * @return AmqpTopic */ public function createTopic($topicName) { @@ -72,36 +75,30 @@ public function createTopic($topicName) } /** - * @param AmqpTopic|PsrDestination $destination + * {@inheritdoc} */ - public function deleteTopic(PsrDestination $destination) + public function deleteTopic(InteropAmqpTopic $topic) { - InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class); - $extExchange = new \AMQPExchange($this->getExtChannel()); - $extExchange->delete($destination->getTopicName(), $destination->getFlags()); + $extExchange->delete($topic->getTopicName(), Flags::convertTopicFlags($topic->getFlags())); } /** - * @param AmqpTopic|PsrDestination $destination + * {@inheritdoc} */ - public function declareTopic(PsrDestination $destination) + public function declareTopic(InteropAmqpTopic $topic) { - InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class); - $extExchange = new \AMQPExchange($this->getExtChannel()); - $extExchange->setName($destination->getTopicName()); - $extExchange->setType($destination->getType()); - $extExchange->setArguments($destination->getArguments()); - $extExchange->setFlags($destination->getFlags()); + $extExchange->setName($topic->getTopicName()); + $extExchange->setType($topic->getType()); + $extExchange->setArguments($topic->getArguments()); + $extExchange->setFlags(Flags::convertTopicFlags($topic->getFlags())); $extExchange->declareExchange(); } /** * {@inheritdoc} - * - * @return AmqpQueue */ public function createQueue($queueName) { @@ -109,54 +106,106 @@ public function createQueue($queueName) } /** - * @param AmqpQueue|PsrDestination $destination + * {@inheritdoc} */ - public function deleteQueue(PsrDestination $destination) + public function deleteQueue(InteropAmqpQueue $queue) { - InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class); - $extQueue = new \AMQPQueue($this->getExtChannel()); - $extQueue->setName($destination->getQueueName()); - $extQueue->delete($destination->getFlags()); + $extQueue->setName($queue->getQueueName()); + $extQueue->delete(Flags::convertQueueFlags($queue->getFlags())); } /** - * @param AmqpQueue|PsrDestination $destination - * - * @return int + * {@inheritdoc} */ - public function declareQueue(PsrDestination $destination) + public function declareQueue(InteropAmqpQueue $queue) { - InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class); - $extQueue = new \AMQPQueue($this->getExtChannel()); - $extQueue->setFlags($destination->getFlags()); - $extQueue->setArguments($destination->getArguments()); + $extQueue->setName($queue->getQueueName()); + $extQueue->setArguments($queue->getArguments()); + $extQueue->setFlags(Flags::convertQueueFlags($queue->getFlags())); + + return $extQueue->declareQueue(); + } + + /** + * {@inheritdoc} + */ + public function purgeQueue(InteropAmqpQueue $queue) + { + $amqpQueue = new \AMQPQueue($this->getExtChannel()); + $amqpQueue->setName($queue->getQueueName()); + $amqpQueue->purge(); + } - if ($destination->getQueueName()) { - $extQueue->setName($destination->getQueueName()); + /** + * {@inheritdoc} + */ + public function bind(InteropAmqpBind $bind) + { + if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { + throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic'); } - $count = $extQueue->declareQueue(); + // bind exchange to exchange + if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { + $exchange = new \AMQPExchange($this->getExtChannel()); + $exchange->setName($bind->getSource()->getTopicName()); + $exchange->bind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + // bind queue to exchange + } elseif ($bind->getSource() instanceof InteropAmqpQueue) { + $queue = new \AMQPQueue($this->getExtChannel()); + $queue->setName($bind->getSource()->getQueueName()); + $queue->bind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + // bind exchange to queue + } else { + $queue = new \AMQPQueue($this->getExtChannel()); + $queue->setName($bind->getTarget()->getQueueName()); + $queue->bind($bind->getSource()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + } + } - if (false == $destination->getQueueName()) { - $destination->setQueueName($extQueue->getName()); + /** + * {@inheritdoc} + */ + public function unbind(InteropAmqpBind $bind) + { + if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { + throw new Exception('Is not possible to unbind queue to queue. It is possible to unbind topic from queue or topic from topic'); } - return $count; + // unbind exchange from exchange + if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { + $exchange = new \AMQPExchange($this->getExtChannel()); + $exchange->setName($bind->getSource()->getTopicName()); + $exchange->unbind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + // unbind queue from exchange + } elseif ($bind->getSource() instanceof InteropAmqpQueue) { + $queue = new \AMQPQueue($this->getExtChannel()); + $queue->setName($bind->getSource()->getQueueName()); + $queue->unbind($bind->getTarget()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + // unbind exchange from queue + } else { + $queue = new \AMQPQueue($this->getExtChannel()); + $queue->setName($bind->getTarget()->getQueueName()); + $queue->unbind($bind->getSource()->getTopicName(), $bind->getRoutingKey(), $bind->getArguments()); + } } /** * {@inheritdoc} * - * @return AmqpQueue + * @return InteropAmqpQueue */ public function createTemporaryQueue() { - $queue = $this->createQueue(null); - $queue->addFlag(AMQP_EXCLUSIVE); + $extQueue = new \AMQPQueue($this->getExtChannel()); + $extQueue->setFlags(AMQP_EXCLUSIVE); + + $extQueue->declareQueue(); - $this->declareQueue($queue); + $queue = $this->createQueue($extQueue->getName()); + $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE); return $queue; } @@ -181,13 +230,13 @@ public function createProducer() public function createConsumer(PsrDestination $destination) { $destination instanceof PsrTopic - ? InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class) - : InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class) + ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class) + : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class) ; if ($destination instanceof AmqpTopic) { $queue = $this->createTemporaryQueue(); - $this->bind($destination, $queue); + $this->bind(new AmqpBind($destination, $queue, $queue->getQueueName())); return new AmqpConsumer($this, $queue, $this->buffer, $this->receiveMethod); } @@ -195,6 +244,9 @@ public function createConsumer(PsrDestination $destination) return new AmqpConsumer($this, $destination, $this->buffer, $this->receiveMethod); } + /** + * {@inheritdoc} + */ public function close() { $extConnection = $this->getExtChannel()->getConnection(); @@ -203,28 +255,6 @@ public function close() } } - /** - * @param AmqpTopic|PsrDestination $source - * @param AmqpQueue|PsrDestination $target - */ - public function bind(PsrDestination $source, PsrDestination $target) - { - InvalidDestinationException::assertDestinationInstanceOf($source, AmqpTopic::class); - InvalidDestinationException::assertDestinationInstanceOf($target, AmqpQueue::class); - - $amqpQueue = new \AMQPQueue($this->getExtChannel()); - $amqpQueue->setName($target->getQueueName()); - $amqpQueue->bind($source->getTopicName(), $amqpQueue->getName(), $target->getBindArguments()); - } - - /** - * @return \AMQPConnection - */ - public function getExtConnection() - { - return $this->getExtChannel()->getConnection(); - } - /** * @return \AMQPChannel */ @@ -244,18 +274,4 @@ public function getExtChannel() return $this->extChannel; } - - /** - * Purge all messages from the given queue. - * - * @param PsrQueue $queue - */ - public function purge(PsrQueue $queue) - { - InvalidDestinationException::assertDestinationInstanceOf($queue, AmqpQueue::class); - - $amqpQueue = new \AMQPQueue($this->getExtChannel()); - $amqpQueue->setName($queue->getQueueName()); - $amqpQueue->purge(); - } } diff --git a/pkg/amqp-ext/AmqpMessage.php b/pkg/amqp-ext/AmqpMessage.php deleted file mode 100644 index b7278ef85..000000000 --- a/pkg/amqp-ext/AmqpMessage.php +++ /dev/null @@ -1,273 +0,0 @@ -body = $body; - $this->properties = $properties; - $this->headers = $headers; - - $this->redelivered = false; - $this->flags = AMQP_NOPARAM; - } - - /** - * {@inheritdoc} - */ - public function getBody() - { - return $this->body; - } - - /** - * {@inheritdoc} - */ - public function setBody($body) - { - $this->body = $body; - } - - /** - * {@inheritdoc} - */ - public function setProperties(array $properties) - { - $this->properties = $properties; - } - - /** - * {@inheritdoc} - */ - public function getProperties() - { - return $this->properties; - } - - /** - * {@inheritdoc} - */ - public function setProperty($name, $value) - { - $this->properties[$name] = $value; - } - - /** - * {@inheritdoc} - */ - public function getProperty($name, $default = null) - { - return array_key_exists($name, $this->properties) ? $this->properties[$name] : $default; - } - - /** - * {@inheritdoc} - */ - public function setHeaders(array $headers) - { - $this->headers = $headers; - } - - /** - * {@inheritdoc} - */ - public function getHeaders() - { - return $this->headers; - } - - /** - * {@inheritdoc} - */ - public function setHeader($name, $value) - { - $this->headers[$name] = $value; - } - - /** - * {@inheritdoc} - */ - public function getHeader($name, $default = null) - { - return array_key_exists($name, $this->headers) ? $this->headers[$name] : $default; - } - - /** - * {@inheritdoc} - */ - public function setRedelivered($redelivered) - { - $this->redelivered = (bool) $redelivered; - } - - /** - * {@inheritdoc} - */ - public function isRedelivered() - { - return $this->redelivered; - } - - /** - * {@inheritdoc} - */ - public function setCorrelationId($correlationId) - { - $this->setHeader('correlation_id', $correlationId); - } - - /** - * {@inheritdoc} - */ - public function getCorrelationId() - { - return $this->getHeader('correlation_id'); - } - - /** - * {@inheritdoc} - */ - public function setMessageId($messageId) - { - $this->setHeader('message_id', $messageId); - } - - /** - * {@inheritdoc} - */ - public function getMessageId() - { - return $this->getHeader('message_id'); - } - - /** - * {@inheritdoc} - */ - public function getTimestamp() - { - $value = $this->getHeader('timestamp'); - - return $value === null ? null : (int) $value; - } - - /** - * {@inheritdoc} - */ - public function setTimestamp($timestamp) - { - $this->setHeader('timestamp', $timestamp); - } - - /** - * {@inheritdoc} - */ - public function setReplyTo($replyTo) - { - $this->setHeader('reply_to', $replyTo); - } - - /** - * {@inheritdoc} - */ - public function getReplyTo() - { - return $this->getHeader('reply_to'); - } - - /** - * @return null|string - */ - public function getDeliveryTag() - { - return $this->deliveryTag; - } - - /** - * @param null|string $deliveryTag - */ - public function setDeliveryTag($deliveryTag) - { - $this->deliveryTag = $deliveryTag; - } - - /** - * @return string|null - */ - public function getConsumerTag() - { - return $this->consumerTag; - } - - /** - * @param string|null $consumerTag - */ - public function setConsumerTag($consumerTag) - { - $this->consumerTag = $consumerTag; - } - - public function clearFlags() - { - $this->flags = AMQP_NOPARAM; - } - - /** - * @param int $flag - */ - public function addFlag($flag) - { - $this->flags = $this->flags | $flag; - } - - /** - * @return int - */ - public function getFlags() - { - return $this->flags; - } -} diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index 0ced3e6b2..ea268de4a 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -2,14 +2,17 @@ namespace Enqueue\AmqpExt; +use Interop\Amqp\AmqpMessage; +use Interop\Amqp\AmqpProducer as InteropAmqpProducer; +use Interop\Amqp\AmqpQueue; +use Interop\Amqp\AmqpTopic; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; use Interop\Queue\PsrMessage; -use Interop\Queue\PsrProducer; use Interop\Queue\PsrTopic; -class AmqpProducer implements PsrProducer +class AmqpProducer implements InteropAmqpProducer { /** * @var \AMQPChannel @@ -49,13 +52,13 @@ public function send(PsrDestination $destination, PsrMessage $message) $amqpExchange = new \AMQPExchange($this->amqpChannel); $amqpExchange->setType($destination->getType()); $amqpExchange->setName($destination->getTopicName()); - $amqpExchange->setFlags($destination->getFlags()); + $amqpExchange->setFlags(Flags::convertTopicFlags($destination->getFlags())); $amqpExchange->setArguments($destination->getArguments()); $amqpExchange->publish( $message->getBody(), - $destination->getRoutingKey(), - $message->getFlags(), + $message->getRoutingKey(), + Flags::convertMessageFlags($message->getFlags()), $amqpAttributes ); } else { @@ -66,7 +69,7 @@ public function send(PsrDestination $destination, PsrMessage $message) $amqpExchange->publish( $message->getBody(), $destination->getQueueName(), - $message->getFlags(), + Flags::convertMessageFlags($message->getFlags()), $amqpAttributes ); } diff --git a/pkg/amqp-ext/AmqpQueue.php b/pkg/amqp-ext/AmqpQueue.php deleted file mode 100644 index bbd0867e2..000000000 --- a/pkg/amqp-ext/AmqpQueue.php +++ /dev/null @@ -1,130 +0,0 @@ -name = $name; - - $this->arguments = []; - $this->bindArguments = []; - $this->flags = AMQP_NOPARAM; - } - - /** - * {@inheritdoc} - */ - public function getQueueName() - { - return $this->name; - } - - /** - * @param string $name - */ - public function setQueueName($name) - { - $this->name = $name; - } - - /** - * @return string - */ - public function getConsumerTag() - { - return $this->consumerTag; - } - - /** - * @param string $consumerTag - */ - public function setConsumerTag($consumerTag) - { - $this->consumerTag = $consumerTag; - } - - /** - * @param int $flag - */ - public function addFlag($flag) - { - $this->flags |= $flag; - } - - public function clearFlags() - { - $this->flags = AMQP_NOPARAM; - } - - /** - * @return int - */ - public function getFlags() - { - return $this->flags; - } - - /** - * @return array - */ - public function getArguments() - { - return $this->arguments; - } - - /** - * @param array $arguments - */ - public function setArguments(array $arguments = null) - { - $this->arguments = $arguments; - } - - /** - * @return array - */ - public function getBindArguments() - { - return $this->bindArguments; - } - - /** - * @param array $arguments - */ - public function setBindArguments(array $arguments = null) - { - $this->bindArguments = $arguments; - } -} diff --git a/pkg/amqp-ext/AmqpTopic.php b/pkg/amqp-ext/AmqpTopic.php deleted file mode 100644 index 784d6ba24..000000000 --- a/pkg/amqp-ext/AmqpTopic.php +++ /dev/null @@ -1,130 +0,0 @@ -name = $name; - - $this->type = AMQP_EX_TYPE_DIRECT; - $this->flags = AMQP_NOPARAM; - $this->arguments = []; - } - - /** - * {@inheritdoc} - */ - public function getTopicName() - { - return $this->name; - } - - /** - * @param string $name - */ - public function setTopicName($name) - { - $this->name = $name; - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @param string $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @param int $flag - */ - public function addFlag($flag) - { - $this->flags |= $flag; - } - - public function clearFlags() - { - $this->flags = AMQP_NOPARAM; - } - - /** - * @return int - */ - public function getFlags() - { - return $this->flags; - } - - /** - * @return array - */ - public function getArguments() - { - return $this->arguments; - } - - /** - * @param array $arguments - */ - public function setArguments(array $arguments = null) - { - $this->arguments = $arguments; - } - - /** - * @return string - */ - public function getRoutingKey() - { - return $this->routingKey; - } - - /** - * @param string $routingKey - */ - public function setRoutingKey($routingKey) - { - $this->routingKey = $routingKey; - } -} diff --git a/pkg/amqp-ext/Buffer.php b/pkg/amqp-ext/Buffer.php index e3f500e29..a192e605b 100644 --- a/pkg/amqp-ext/Buffer.php +++ b/pkg/amqp-ext/Buffer.php @@ -2,6 +2,8 @@ namespace Enqueue\AmqpExt; +use Interop\Amqp\AmqpMessage; + class Buffer { /** diff --git a/pkg/amqp-ext/Flags.php b/pkg/amqp-ext/Flags.php new file mode 100644 index 000000000..e433250da --- /dev/null +++ b/pkg/amqp-ext/Flags.php @@ -0,0 +1,124 @@ +createConsumer($queue); -$fooConsumer->receive(1); -$barConsumer->receive(1); - $consumers = [$fooConsumer, $barConsumer]; $consumer = $consumers[rand(0, 1)]; diff --git a/pkg/amqp-ext/examples/produce.php b/pkg/amqp-ext/examples/produce.php index 8c29dcdf2..2928ed24f 100644 --- a/pkg/amqp-ext/examples/produce.php +++ b/pkg/amqp-ext/examples/produce.php @@ -16,6 +16,9 @@ } use Enqueue\AmqpExt\AmqpConnectionFactory; +use Interop\Amqp\AmqpTopic; +use Interop\Amqp\AmqpQueue; +use Interop\Amqp\Impl\AmqpBind; $config = [ 'host' => getenv('SYMFONY__RABBITMQ__HOST'), @@ -29,28 +32,28 @@ $context = $factory->createContext(); $topic = $context->createTopic('test.amqp.ext'); -$topic->addFlag(AMQP_DURABLE); -$topic->setType(AMQP_EX_TYPE_FANOUT); +$topic->addFlag(AmqpTopic::FLAG_DURABLE); +$topic->setType(AmqpTopic::TYPE_FANOUT); $topic->setArguments(['alternate-exchange' => 'foo']); $context->deleteTopic($topic); $context->declareTopic($topic); $fooQueue = $context->createQueue('foo'); -$fooQueue->addFlag(AMQP_DURABLE); +$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE); $context->deleteQueue($fooQueue); $context->declareQueue($fooQueue); -$context->bind($topic, $fooQueue); +$context->bind(new AmqpBind($topic, $fooQueue)); $barQueue = $context->createQueue('bar'); -$barQueue->addFlag(AMQP_DURABLE); +$barQueue->addFlag(AmqpQueue::FLAG_DURABLE); $context->deleteQueue($barQueue); $context->declareQueue($barQueue); -$context->bind($topic, $barQueue); +$context->bind(new AmqpBind($topic, $barQueue)); $message = $context->createMessage('Hello Bar!'); From bb789a75d92fd94d46aab3204305c1dd6e8c10a4 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Tue, 25 Jul 2017 16:17:30 +0300 Subject: [PATCH 10/76] amqp ext interop --- pkg/amqp-ext/Client/AmqpDriver.php | 35 ++++++++++++-------------- pkg/amqp-ext/Client/RabbitMqDriver.php | 16 ++++++------ pkg/amqp-ext/examples/consume.php | 6 ++--- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/pkg/amqp-ext/Client/AmqpDriver.php b/pkg/amqp-ext/Client/AmqpDriver.php index a1d918ca4..0a636518d 100644 --- a/pkg/amqp-ext/Client/AmqpDriver.php +++ b/pkg/amqp-ext/Client/AmqpDriver.php @@ -3,14 +3,14 @@ namespace Enqueue\AmqpExt\Client; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\AmqpMessage; -use Enqueue\AmqpExt\AmqpQueue; -use Enqueue\AmqpExt\AmqpTopic; -use Enqueue\AmqpExt\DeliveryMode; use Enqueue\Client\Config; use Enqueue\Client\DriverInterface; use Enqueue\Client\Message; use Enqueue\Client\Meta\QueueMetaRegistry; +use Interop\Amqp\AmqpMessage; +use Interop\Amqp\AmqpQueue; +use Interop\Amqp\AmqpTopic; +use Interop\Amqp\Impl\AmqpBind; use Interop\Queue\PsrMessage; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -97,7 +97,7 @@ public function setupBroker(LoggerInterface $logger = null) $log('Declare router queue: %s', $routerQueue->getQueueName()); $this->context->declareQueue($routerQueue); $log('Bind router queue to exchange: %s -> %s', $routerQueue->getQueueName(), $routerTopic->getTopicName()); - $this->context->bind($routerTopic, $routerQueue); + $this->context->bind(new AmqpBind($routerTopic, $routerQueue, $routerQueue->getQueueName())); // setup queues foreach ($this->queueMetaRegistry->getQueuesMeta() as $meta) { @@ -118,7 +118,7 @@ public function createQueue($queueName) $transportName = $this->queueMetaRegistry->getQueueMeta($queueName)->getTransportName(); $queue = $this->context->createQueue($transportName); - $queue->addFlag(AMQP_DURABLE); + $queue->addFlag(AmqpQueue::FLAG_DURABLE); return $queue; } @@ -133,14 +133,6 @@ public function createTransportMessage(Message $message) $headers = $message->getHeaders(); $properties = $message->getProperties(); - $headers['content_type'] = $message->getContentType(); - - if ($message->getExpire()) { - $headers['expiration'] = (string) ($message->getExpire() * 1000); - } - - $headers['delivery_mode'] = DeliveryMode::PERSISTENT; - $transportMessage = $this->context->createMessage(); $transportMessage->setBody($message->getBody()); $transportMessage->setHeaders($headers); @@ -149,6 +141,12 @@ public function createTransportMessage(Message $message) $transportMessage->setTimestamp($message->getTimestamp()); $transportMessage->setReplyTo($message->getReplyTo()); $transportMessage->setCorrelationId($message->getCorrelationId()); + $transportMessage->setContentType($message->getContentType()); + $transportMessage->setDeliveryMode(AmqpMessage::DELIVERY_MODE_PERSISTENT); + + if ($message->getExpire()) { + $transportMessage->setExpiration((string) ($message->getExpire() * 1000)); + } return $transportMessage; } @@ -165,10 +163,9 @@ public function createClientMessage(PsrMessage $message) $clientMessage->setBody($message->getBody()); $clientMessage->setHeaders($message->getHeaders()); $clientMessage->setProperties($message->getProperties()); + $clientMessage->setContentType($message->getContentType()); - $clientMessage->setContentType($message->getHeader('content_type')); - - if ($expiration = $message->getHeader('expiration')) { + if ($expiration = $message->getExpiration()) { if (false == is_numeric($expiration)) { throw new \LogicException(sprintf('expiration header is not numeric. "%s"', $expiration)); } @@ -200,8 +197,8 @@ private function createRouterTopic() $topic = $this->context->createTopic( $this->config->createTransportRouterTopicName($this->config->getRouterTopicName()) ); - $topic->setType(AMQP_EX_TYPE_FANOUT); - $topic->addFlag(AMQP_DURABLE); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); return $topic; } diff --git a/pkg/amqp-ext/Client/RabbitMqDriver.php b/pkg/amqp-ext/Client/RabbitMqDriver.php index 2254ea448..6815bfe59 100644 --- a/pkg/amqp-ext/Client/RabbitMqDriver.php +++ b/pkg/amqp-ext/Client/RabbitMqDriver.php @@ -3,14 +3,15 @@ namespace Enqueue\AmqpExt\Client; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\AmqpMessage; -use Enqueue\AmqpExt\AmqpQueue; -use Enqueue\AmqpExt\AmqpTopic; use Enqueue\Client\Config; use Enqueue\Client\Message; use Enqueue\Client\MessagePriority; use Enqueue\Client\Meta\QueueMetaRegistry; use Enqueue\Consumption\Exception\LogicException; +use Interop\Amqp\AmqpMessage; +use Interop\Amqp\AmqpQueue; +use Interop\Amqp\AmqpTopic; +use Interop\Amqp\Impl\AmqpBind; use Interop\Queue\PsrMessage; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; @@ -112,7 +113,7 @@ public function createTransportMessage(Message $message) )); } - $transportMessage->setHeader('priority', $this->priorityMap[$priority]); + $transportMessage->setPriority($this->priorityMap[$priority]); } if ($message->getDelay()) { @@ -135,7 +136,7 @@ public function createClientMessage(PsrMessage $message) { $clientMessage = parent::createClientMessage($message); - if ($priority = $message->getHeader('priority')) { + if ($priority = $message->getPriority()) { if (false === $clientPriority = array_search($priority, $this->priorityMap, true)) { throw new \LogicException(sprintf('Cant convert transport priority to client: "%s"', $priority)); } @@ -178,7 +179,7 @@ public function setupBroker(LoggerInterface $logger = null) $this->context->declareTopic($delayTopic); $log('Bind processor queue to delay exchange: %s -> %s', $queue->getQueueName(), $delayTopic->getTopicName()); - $this->context->bind($delayTopic, $queue); + $this->context->bind(new AmqpBind($delayTopic, $queue , $queue->getQueueName())); } } } @@ -194,9 +195,8 @@ private function createDelayedTopic(AmqpQueue $queue) // in order to use delay feature make sure the rabbitmq_delayed_message_exchange plugin is installed. $delayTopic = $this->context->createTopic($queueName.'.delayed'); - $delayTopic->setRoutingKey($queueName); $delayTopic->setType('x-delayed-message'); - $delayTopic->addFlag(AMQP_DURABLE); + $delayTopic->addFlag(AmqpTopic::FLAG_DURABLE); $delayTopic->setArguments([ 'x-delayed-type' => 'direct', ]); diff --git a/pkg/amqp-ext/examples/consume.php b/pkg/amqp-ext/examples/consume.php index 71c44cfc3..ece61b1d4 100644 --- a/pkg/amqp-ext/examples/consume.php +++ b/pkg/amqp-ext/examples/consume.php @@ -34,17 +34,17 @@ $queue = $context->createQueue('bar'); $barConsumer = $context->createConsumer($queue); -$consumer = $context->createConsumer($queue); - $consumers = [$fooConsumer, $barConsumer]; $consumer = $consumers[rand(0, 1)]; while (true) { if ($m = $consumer->receive(1)) { - $consumer = $consumers[rand(0, 1)]; + echo $m->getBody(), PHP_EOL; $consumer->acknowledge($m); } + + $consumer = $consumers[rand(0, 1)]; } echo 'Done'."\n"; From 25c511f5ade5505d8e1a00e2237a9b37ee5d3115 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Wed, 26 Jul 2017 10:25:19 +0300 Subject: [PATCH 11/76] amqp ext interop --- pkg/amqp-ext/Tests/AmqpConsumerTest.php | 2 +- pkg/amqp-ext/Tests/AmqpContextTest.php | 81 ++---------- pkg/amqp-ext/Tests/AmqpMessageTest.php | 118 ------------------ pkg/amqp-ext/Tests/AmqpQueueTest.php | 103 --------------- pkg/amqp-ext/Tests/AmqpTopicTest.php | 115 ----------------- pkg/amqp-ext/Tests/BufferTest.php | 2 +- pkg/amqp-ext/Tests/Client/AmqpDriverTest.php | 16 +-- .../Tests/Client/RabbitMqDriverTest.php | 20 +-- .../Functional/AmqpCommonUseCasesTest.php | 2 +- .../Tests/Functional/AmqpRpcUseCasesTest.php | 2 +- pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php | 2 +- .../AmqpSendToAndReceiveFromQueueTest.php | 2 +- .../AmqpSendToAndReceiveFromTopicTest.php | 5 +- ...mqpSendToAndReceiveNoWaitFromQueueTest.php | 2 +- ...mqpSendToAndReceiveNoWaitFromTopicTest.php | 5 +- ...AmqpSendToTopicAndReceiveFromQueueTest.php | 7 +- ...ndToTopicAndReceiveNoWaitFromQueueTest.php | 10 +- 17 files changed, 49 insertions(+), 445 deletions(-) delete mode 100644 pkg/amqp-ext/Tests/AmqpMessageTest.php delete mode 100644 pkg/amqp-ext/Tests/AmqpQueueTest.php delete mode 100644 pkg/amqp-ext/Tests/AmqpTopicTest.php diff --git a/pkg/amqp-ext/Tests/AmqpConsumerTest.php b/pkg/amqp-ext/Tests/AmqpConsumerTest.php index 1927cc2c9..5d184c321 100644 --- a/pkg/amqp-ext/Tests/AmqpConsumerTest.php +++ b/pkg/amqp-ext/Tests/AmqpConsumerTest.php @@ -4,9 +4,9 @@ use Enqueue\AmqpExt\AmqpConsumer; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\AmqpQueue; use Enqueue\AmqpExt\Buffer; use Enqueue\Test\ClassExtensionTrait; +use Interop\Amqp\Impl\AmqpQueue; use Interop\Queue\PsrConsumer; use PHPUnit\Framework\TestCase; diff --git a/pkg/amqp-ext/Tests/AmqpContextTest.php b/pkg/amqp-ext/Tests/AmqpContextTest.php index aa152a6f4..d3ed3a671 100644 --- a/pkg/amqp-ext/Tests/AmqpContextTest.php +++ b/pkg/amqp-ext/Tests/AmqpContextTest.php @@ -4,14 +4,14 @@ use Enqueue\AmqpExt\AmqpConsumer; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\AmqpMessage; use Enqueue\AmqpExt\AmqpProducer; -use Enqueue\AmqpExt\AmqpQueue; -use Enqueue\AmqpExt\AmqpTopic; use Enqueue\AmqpExt\Buffer; use Enqueue\Null\NullQueue; use Enqueue\Null\NullTopic; use Enqueue\Test\ClassExtensionTrait; +use Interop\Amqp\Impl\AmqpMessage; +use Interop\Amqp\Impl\AmqpQueue; +use Interop\Amqp\Impl\AmqpTopic; use Interop\Queue\InvalidDestinationException; use Interop\Queue\PsrContext; use PHPUnit\Framework\TestCase; @@ -86,27 +86,8 @@ public function testShouldCreateTopicWithGivenName() $this->assertInstanceOf(AmqpTopic::class, $topic); $this->assertSame('theName', $topic->getTopicName()); - $this->assertSame(\AMQP_NOPARAM, $topic->getFlags()); + $this->assertSame(AmqpTopic::FLAG_NOPARAM, $topic->getFlags()); $this->assertSame([], $topic->getArguments()); - $this->assertSame(null, $topic->getRoutingKey()); - } - - public function testShouldThrowIfNotAmqpTopicGivenOnDeleteTopicCall() - { - $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpTopic but got Enqueue\Null\NullTopic.'); - $context->deleteTopic(new NullTopic('aName')); - } - - public function testShouldThrowIfNotAmqpTopicGivenOnDeclareTopicCall() - { - $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpTopic but got Enqueue\Null\NullTopic.'); - $context->declareTopic(new NullTopic('aName')); } public function testShouldCreateQueueWithGivenName() @@ -117,30 +98,11 @@ public function testShouldCreateQueueWithGivenName() $this->assertInstanceOf(AmqpQueue::class, $queue); $this->assertSame('theName', $queue->getQueueName()); - $this->assertSame(\AMQP_NOPARAM, $queue->getFlags()); + $this->assertSame(AmqpQueue::FLAG_NOPARAM, $queue->getFlags()); $this->assertSame([], $queue->getArguments()); - $this->assertSame([], $queue->getBindArguments()); $this->assertSame(null, $queue->getConsumerTag()); } - public function testShouldThrowIfNotAmqpQueueGivenOnDeleteQueueCall() - { - $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.'); - $context->deleteQueue(new NullQueue('aName')); - } - - public function testShouldThrowIfNotAmqpQueueGivenOnDeclareQueueCall() - { - $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.'); - $context->declareQueue(new NullQueue('aName')); - } - public function testShouldReturnAmqpProducer() { $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); @@ -172,7 +134,7 @@ public function testShouldThrowIfNotAmqpQueueGivenOnCreateConsumerCall() $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.'); + $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpQueue but got Enqueue\Null\NullQueue.'); $context->createConsumer(new NullQueue('aName')); } @@ -181,11 +143,11 @@ public function testShouldThrowIfNotAmqpTopicGivenOnCreateConsumerCall() $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpTopic but got Enqueue\Null\NullTopic.'); + $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpTopic but got Enqueue\Null\NullTopic.'); $context->createConsumer(new NullTopic('aName')); } - public function shouldDoNothingIfConnectionAlreadyClosed() + public function testShouldDoNothingIfConnectionAlreadyClosed() { $extConnectionMock = $this->createExtConnectionMock(); $extConnectionMock @@ -286,33 +248,6 @@ public function testShouldClosePersistedConnection() $context->close(); } - public function testShouldThrowIfSourceNotAmqpTopicOnBindCall() - { - $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpTopic but got Enqueue\Null\NullTopic.'); - $context->bind(new NullTopic('aName'), new AmqpQueue('aName')); - } - - public function testShouldThrowIfTargetNotAmqpQueueOnBindCall() - { - $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.'); - $context->bind(new AmqpTopic('aName'), new NullQueue('aName')); - } - - public function testShouldThrowIfGivenQueueNotAmqpQueueOnPurge() - { - $context = new AmqpContext($this->createExtChannelMock(), 'basic_get'); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpExt\AmqpQueue but got Enqueue\Null\NullQueue.'); - $context->purge(new NullQueue('aName')); - } - /** * @return \PHPUnit_Framework_MockObject_MockObject|\AMQPChannel */ diff --git a/pkg/amqp-ext/Tests/AmqpMessageTest.php b/pkg/amqp-ext/Tests/AmqpMessageTest.php deleted file mode 100644 index a8674b0fa..000000000 --- a/pkg/amqp-ext/Tests/AmqpMessageTest.php +++ /dev/null @@ -1,118 +0,0 @@ -assertClassImplements(PsrMessage::class, AmqpMessage::class); - } - - public function testCouldBeConstructedWithoutArguments() - { - $message = new AmqpMessage(); - - $this->assertSame('', $message->getBody()); - $this->assertSame([], $message->getProperties()); - $this->assertSame([], $message->getHeaders()); - } - - public function testCouldBeConstructedWithOptionalArguments() - { - $message = new AmqpMessage('theBody', ['barProp' => 'barPropVal'], ['fooHeader' => 'fooHeaderVal']); - - $this->assertSame('theBody', $message->getBody()); - $this->assertSame(['barProp' => 'barPropVal'], $message->getProperties()); - $this->assertSame(['fooHeader' => 'fooHeaderVal'], $message->getHeaders()); - } - - public function testShouldSetNoParamFlagInConstructor() - { - $message = new AmqpMessage(); - - $this->assertSame(\AMQP_NOPARAM, $message->getFlags()); - } - - public function testShouldSetCorrelationIdAsHeader() - { - $message = new AmqpMessage(); - $message->setCorrelationId('theCorrelationId'); - - $this->assertSame(['correlation_id' => 'theCorrelationId'], $message->getHeaders()); - } - - public function testShouldSetSetMessageIdAsHeader() - { - $message = new AmqpMessage(); - $message->setMessageId('theMessageId'); - - $this->assertSame(['message_id' => 'theMessageId'], $message->getHeaders()); - } - - public function testShouldSetTimestampAsHeader() - { - $message = new AmqpMessage(); - $message->setTimestamp('theTimestamp'); - - $this->assertSame(['timestamp' => 'theTimestamp'], $message->getHeaders()); - } - - public function testShouldSetReplyToAsHeader() - { - $message = new AmqpMessage(); - $message->setReplyTo('theReply'); - - $this->assertSame(['reply_to' => 'theReply'], $message->getHeaders()); - } - - public function testShouldReturnPreviouslySetDeliveryTag() - { - $message = new AmqpMessage(); - - $message->setDeliveryTag('theDeliveryTag'); - - $this->assertSame('theDeliveryTag', $message->getDeliveryTag()); - } - - public function testShouldReturnPreviouslySetConsumerTag() - { - $message = new AmqpMessage(); - - $message->setConsumerTag('theConsumerTag'); - - $this->assertSame('theConsumerTag', $message->getConsumerTag()); - } - - public function testShouldAllowAddFlags() - { - $message = new AmqpMessage(); - - $message->addFlag(AMQP_DURABLE); - $message->addFlag(AMQP_PASSIVE); - - $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $message->getFlags()); - } - - public function testShouldClearPreviouslySetFlags() - { - $message = new AmqpMessage(); - - $message->addFlag(AMQP_DURABLE); - $message->addFlag(AMQP_PASSIVE); - - //guard - $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $message->getFlags()); - - $message->clearFlags(); - - $this->assertSame(AMQP_NOPARAM, $message->getFlags()); - } -} diff --git a/pkg/amqp-ext/Tests/AmqpQueueTest.php b/pkg/amqp-ext/Tests/AmqpQueueTest.php deleted file mode 100644 index 63cd7e42c..000000000 --- a/pkg/amqp-ext/Tests/AmqpQueueTest.php +++ /dev/null @@ -1,103 +0,0 @@ -assertClassImplements(PsrQueue::class, AmqpQueue::class); - } - - public function testCouldBeConstructedWithQueueNameArgument() - { - new AmqpQueue('aName'); - } - - public function testShouldReturnQueueNameSetInConstructor() - { - $queue = new AmqpQueue('theName'); - - $this->assertSame('theName', $queue->getQueueName()); - } - - public function testShouldReturnPreviouslySetQueueName() - { - $queue = new AmqpQueue('aName'); - - $queue->setQueueName('theAnotherQueueName'); - - $this->assertSame('theAnotherQueueName', $queue->getQueueName()); - } - - public function testShouldSetEmptyArrayAsArgumentsInConstructor() - { - $queue = new AmqpQueue('aName'); - - $this->assertSame([], $queue->getArguments()); - } - - public function testShouldSetEmptyArrayAsBindArgumentsInConstructor() - { - $queue = new AmqpQueue('aName'); - - $this->assertSame([], $queue->getBindArguments()); - } - - public function testShouldSetNoParamFlagInConstructor() - { - $queue = new AmqpQueue('aName'); - - $this->assertSame(AMQP_NOPARAM, $queue->getFlags()); - } - - public function testShouldAllowAddFlags() - { - $queue = new AmqpQueue('aName'); - - $queue->addFlag(AMQP_DURABLE); - $queue->addFlag(AMQP_PASSIVE); - - $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $queue->getFlags()); - } - - public function testShouldClearPreviouslySetFlags() - { - $queue = new AmqpQueue('aName'); - - $queue->addFlag(AMQP_DURABLE); - $queue->addFlag(AMQP_PASSIVE); - - //guard - $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $queue->getFlags()); - - $queue->clearFlags(); - - $this->assertSame(AMQP_NOPARAM, $queue->getFlags()); - } - - public function testShouldAllowGetPreviouslySetArguments() - { - $queue = new AmqpQueue('aName'); - - $queue->setArguments(['foo' => 'fooVal', 'bar' => 'barVal']); - - $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $queue->getArguments()); - } - - public function testShouldAllowGetPreviouslySetBindArguments() - { - $queue = new AmqpQueue('aName'); - - $queue->setBindArguments(['foo' => 'fooVal', 'bar' => 'barVal']); - - $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $queue->getBindArguments()); - } -} diff --git a/pkg/amqp-ext/Tests/AmqpTopicTest.php b/pkg/amqp-ext/Tests/AmqpTopicTest.php deleted file mode 100644 index 3a0c2bd56..000000000 --- a/pkg/amqp-ext/Tests/AmqpTopicTest.php +++ /dev/null @@ -1,115 +0,0 @@ -assertClassImplements(PsrTopic::class, AmqpTopic::class); - } - - public function testCouldBeConstructedWithTopicNameAsArgument() - { - new AmqpTopic('aName'); - } - - public function testShouldReturnTopicNameSetInConstructor() - { - $topic = new AmqpTopic('theName'); - - $this->assertSame('theName', $topic->getTopicName()); - } - - public function testShouldReturnPreviouslySetTopicName() - { - $topic = new AmqpTopic('aName'); - - $topic->setTopicName('theAnotherTopicName'); - - $this->assertSame('theAnotherTopicName', $topic->getTopicName()); - } - - public function testShouldSetEmptyArrayAsArgumentsInConstructor() - { - $topic = new AmqpTopic('aName'); - - $this->assertSame([], $topic->getArguments()); - } - - public function testShouldSetDirectTypeInConstructor() - { - $topic = new AmqpTopic('aName'); - - $this->assertSame(\AMQP_EX_TYPE_DIRECT, $topic->getType()); - } - - public function testShouldSetNoParamFlagInConstructor() - { - $topic = new AmqpTopic('aName'); - - $this->assertSame(AMQP_NOPARAM, $topic->getFlags()); - } - - public function testShouldAllowAddFlags() - { - $topic = new AmqpTopic('aName'); - - $topic->addFlag(AMQP_DURABLE); - $topic->addFlag(AMQP_PASSIVE); - - $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $topic->getFlags()); - } - - public function testShouldClearPreviouslySetFlags() - { - $topic = new AmqpTopic('aName'); - - $topic->addFlag(AMQP_DURABLE); - $topic->addFlag(AMQP_PASSIVE); - - //guard - $this->assertSame(AMQP_DURABLE | AMQP_PASSIVE, $topic->getFlags()); - - $topic->clearFlags(); - - $this->assertSame(AMQP_NOPARAM, $topic->getFlags()); - } - - public function testShouldAllowGetPreviouslySetArguments() - { - $topic = new AmqpTopic('aName'); - - $topic->setArguments(['foo' => 'fooVal', 'bar' => 'barVal']); - - $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $topic->getArguments()); - } - - public function testShouldAllowGetPreviouslySetType() - { - $topic = new AmqpTopic('aName'); - - $topic->setType(\AMQP_EX_TYPE_FANOUT); - - $this->assertSame(\AMQP_EX_TYPE_FANOUT, $topic->getType()); - } - - public function testShouldAllowGetPreviouslySetRoutingKey() - { - $topic = new AmqpTopic('aName'); - - //guard - $this->assertSame(null, $topic->getRoutingKey()); - - $topic->setRoutingKey('theRoutingKey'); - - $this->assertSame('theRoutingKey', $topic->getRoutingKey()); - } -} diff --git a/pkg/amqp-ext/Tests/BufferTest.php b/pkg/amqp-ext/Tests/BufferTest.php index 151481f91..977365ce6 100644 --- a/pkg/amqp-ext/Tests/BufferTest.php +++ b/pkg/amqp-ext/Tests/BufferTest.php @@ -2,8 +2,8 @@ namespace Enqueue\AmqpExt\Tests; -use Enqueue\AmqpExt\AmqpMessage; use Enqueue\AmqpExt\Buffer; +use Interop\Amqp\Impl\AmqpMessage; use PHPUnit\Framework\TestCase; class BufferTest extends TestCase diff --git a/pkg/amqp-ext/Tests/Client/AmqpDriverTest.php b/pkg/amqp-ext/Tests/Client/AmqpDriverTest.php index 9484dbc2c..990f7a5ea 100644 --- a/pkg/amqp-ext/Tests/Client/AmqpDriverTest.php +++ b/pkg/amqp-ext/Tests/Client/AmqpDriverTest.php @@ -3,15 +3,16 @@ namespace Enqueue\AmqpExt\Tests\Client; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\AmqpMessage; -use Enqueue\AmqpExt\AmqpQueue; -use Enqueue\AmqpExt\AmqpTopic; use Enqueue\AmqpExt\Client\AmqpDriver; use Enqueue\Client\Config; use Enqueue\Client\DriverInterface; use Enqueue\Client\Message; use Enqueue\Client\Meta\QueueMetaRegistry; use Enqueue\Test\ClassExtensionTrait; +use Interop\Amqp\Impl\AmqpBind; +use Interop\Amqp\Impl\AmqpMessage; +use Interop\Amqp\Impl\AmqpQueue; +use Interop\Amqp\Impl\AmqpTopic; use Interop\Queue\PsrProducer; use PHPUnit\Framework\TestCase; @@ -62,7 +63,6 @@ public function testShouldCreateAndReturnQueueInstance() $this->assertSame([], $queue->getArguments()); $this->assertSame(2, $queue->getFlags()); $this->assertNull($queue->getConsumerTag()); - $this->assertSame([], $queue->getBindArguments()); } public function testShouldCreateAndReturnQueueInstanceWithHardcodedTransportName() @@ -176,13 +176,13 @@ public function testShouldConvertClientMessageToTransportMessage() $this->assertSame('body', $transportMessage->getBody()); $this->assertSame([ 'hkey' => 'hval', - 'content_type' => 'ContentType', - 'expiration' => '123000', - 'delivery_mode' => 2, 'message_id' => 'MessageId', 'timestamp' => 1000, 'reply_to' => 'theReplyTo', 'correlation_id' => 'theCorrelationId', + 'content_type' => 'ContentType', + 'delivery_mode' => 2, + 'expiration' => '123000', ], $transportMessage->getHeaders()); $this->assertSame([ 'key' => 'val', @@ -351,7 +351,7 @@ public function testShouldSetupBroker() $context ->expects($this->at(4)) ->method('bind') - ->with($this->identicalTo($routerTopic), $this->identicalTo($routerQueue)) + ->with($this->isInstanceOf(AmqpBind::class)) ; // setup processor queue $context diff --git a/pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php b/pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php index edb66ffb2..ac3e0dba9 100644 --- a/pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php +++ b/pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php @@ -3,9 +3,6 @@ namespace Enqueue\AmqpExt\Tests\Client; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\AmqpMessage; -use Enqueue\AmqpExt\AmqpQueue; -use Enqueue\AmqpExt\AmqpTopic; use Enqueue\AmqpExt\Client\AmqpDriver; use Enqueue\AmqpExt\Client\RabbitMqDriver; use Enqueue\Client\Config; @@ -14,6 +11,10 @@ use Enqueue\Client\MessagePriority; use Enqueue\Client\Meta\QueueMetaRegistry; use Enqueue\Test\ClassExtensionTrait; +use Interop\Amqp\AmqpBind; +use Interop\Amqp\Impl\AmqpMessage; +use Interop\Amqp\Impl\AmqpQueue; +use Interop\Amqp\Impl\AmqpTopic; use Interop\Queue\PsrProducer; use PHPUnit\Framework\TestCase; @@ -69,7 +70,6 @@ public function testShouldCreateAndReturnQueueInstance() $this->assertSame([], $queue->getArguments()); $this->assertSame(2, $queue->getFlags()); $this->assertNull($queue->getConsumerTag()); - $this->assertSame([], $queue->getBindArguments()); } public function testShouldCreateAndReturnQueueInstanceWithHardcodedTransportName() @@ -249,13 +249,13 @@ public function testShouldConvertClientMessageToTransportMessage() $this->assertSame('body', $transportMessage->getBody()); $this->assertSame([ 'hkey' => 'hval', - 'content_type' => 'ContentType', - 'expiration' => '123000', - 'delivery_mode' => 2, 'message_id' => 'MessageId', 'timestamp' => 1000, 'reply_to' => 'theReplyTo', 'correlation_id' => 'theCorrelationId', + 'content_type' => 'ContentType', + 'delivery_mode' => 2, + 'expiration' => '123000', 'priority' => 4, ], $transportMessage->getHeaders()); $this->assertSame([ @@ -498,7 +498,7 @@ public function testShouldSetupBrokerWhenDelayPluginNotInstalled() $context ->expects($this->at(4)) ->method('bind') - ->with($this->identicalTo($routerTopic), $this->identicalTo($routerQueue)) + ->with($this->isInstanceOf(AmqpBind::class)) ; // setup processor queue $context @@ -549,7 +549,7 @@ public function testShouldSetupBroker() $context ->expects($this->at(4)) ->method('bind') - ->with($this->identicalTo($routerTopic), $this->identicalTo($routerQueue)) + ->with($this->isInstanceOf(AmqpBind::class)) ; // setup processor queue $context @@ -581,7 +581,7 @@ public function testShouldSetupBroker() $context ->expects($this->at(10)) ->method('bind') - ->with($this->identicalTo($delayTopic), $this->identicalTo($processorQueue)) + ->with($this->isInstanceOf(AmqpBind::class)) ; $config = Config::create('', '', '', '', '', '', ['delay_plugin_installed' => true]); diff --git a/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php b/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php index 70a2c2605..910ce1d47 100644 --- a/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php +++ b/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php @@ -3,9 +3,9 @@ namespace Enqueue\AmqpExt\Tests\Functional; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\AmqpMessage; use Enqueue\Test\RabbitmqAmqpExtension; use Enqueue\Test\RabbitmqManagmentExtensionTrait; +use Interop\Amqp\Impl\AmqpMessage; use PHPUnit\Framework\TestCase; /** diff --git a/pkg/amqp-ext/Tests/Functional/AmqpRpcUseCasesTest.php b/pkg/amqp-ext/Tests/Functional/AmqpRpcUseCasesTest.php index 197afa836..3db7ec63c 100644 --- a/pkg/amqp-ext/Tests/Functional/AmqpRpcUseCasesTest.php +++ b/pkg/amqp-ext/Tests/Functional/AmqpRpcUseCasesTest.php @@ -3,11 +3,11 @@ namespace Enqueue\AmqpExt\Tests\Functional; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\AmqpMessage; use Enqueue\Rpc\Promise; use Enqueue\Rpc\RpcClient; use Enqueue\Test\RabbitmqAmqpExtension; use Enqueue\Test\RabbitmqManagmentExtensionTrait; +use Interop\Amqp\Impl\AmqpMessage; use PHPUnit\Framework\TestCase; /** diff --git a/pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php b/pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php index aa32ea893..ea36b648c 100644 --- a/pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpMessageTest.php @@ -2,7 +2,7 @@ namespace Enqueue\AmqpExt\Tests\Spec; -use Enqueue\AmqpExt\AmqpMessage; +use Interop\Amqp\Impl\AmqpMessage; use Interop\Queue\Spec\PsrMessageSpec; class AmqpMessageTest extends PsrMessageSpec diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php index f2068feb2..92436483b 100644 --- a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php @@ -31,7 +31,7 @@ protected function createQueue(PsrContext $context, $queueName) { $queue = $context->createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); return $queue; } diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php index be99e3f1f..c13da615e 100644 --- a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php @@ -4,6 +4,7 @@ use Enqueue\AmqpExt\AmqpConnectionFactory; use Enqueue\AmqpExt\AmqpContext; +use Interop\Amqp\AmqpTopic; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToAndReceiveFromTopicSpec; @@ -30,8 +31,8 @@ protected function createContext() protected function createTopic(PsrContext $context, $topicName) { $topic = $context->createTopic($topicName); - $topic->setType(\AMQP_EX_TYPE_FANOUT); - $topic->addFlag(\AMQP_DURABLE); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php index 25431d54e..dd5035efa 100644 --- a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php @@ -31,7 +31,7 @@ protected function createQueue(PsrContext $context, $queueName) { $queue = $context->createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); return $queue; } diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php index d3993220e..2db18a6ce 100644 --- a/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php @@ -4,6 +4,7 @@ use Enqueue\AmqpExt\AmqpConnectionFactory; use Enqueue\AmqpExt\AmqpContext; +use Interop\Amqp\AmqpTopic; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToAndReceiveNoWaitFromTopicSpec; @@ -30,8 +31,8 @@ protected function createContext() protected function createTopic(PsrContext $context, $topicName) { $topic = $context->createTopic($topicName); - $topic->setType(\AMQP_EX_TYPE_FANOUT); - $topic->addFlag(\AMQP_DURABLE); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php index 8c01e552c..e2191ce2e 100644 --- a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php @@ -4,6 +4,7 @@ use Enqueue\AmqpExt\AmqpConnectionFactory; use Enqueue\AmqpExt\AmqpContext; +use Interop\Amqp\AmqpTopic; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToTopicAndReceiveFromQueueSpec; @@ -31,7 +32,7 @@ protected function createQueue(PsrContext $context, $queueName) { $queue = $context->createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); $context->bind($context->createTopic($queueName), $queue); @@ -46,8 +47,8 @@ protected function createQueue(PsrContext $context, $queueName) protected function createTopic(PsrContext $context, $topicName) { $topic = $context->createTopic($topicName); - $topic->setType(\AMQP_EX_TYPE_FANOUT); - $topic->addFlag(\AMQP_DURABLE); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php index bdb27f13d..fa6633052 100644 --- a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php @@ -4,6 +4,8 @@ use Enqueue\AmqpExt\AmqpConnectionFactory; use Enqueue\AmqpExt\AmqpContext; +use Interop\Amqp\AmqpTopic; +use Interop\Amqp\Impl\AmqpBind; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToTopicAndReceiveNoWaitFromQueueSpec; @@ -31,9 +33,9 @@ protected function createQueue(PsrContext $context, $queueName) { $queue = $context->createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); - $context->bind($context->createTopic($queueName), $queue); + $context->bind(new AmqpBind($context->createTopic($queueName), $queue)); return $queue; } @@ -46,8 +48,8 @@ protected function createQueue(PsrContext $context, $queueName) protected function createTopic(PsrContext $context, $topicName) { $topic = $context->createTopic($topicName); - $topic->setType(\AMQP_EX_TYPE_FANOUT); - $topic->addFlag(\AMQP_DURABLE); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; From 7ac2feadc4484bb767a795b4602a1265a7643e92 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Wed, 26 Jul 2017 10:37:04 +0300 Subject: [PATCH 12/76] amqp ext interop --- pkg/amqp-ext/AmqpContext.php | 6 +++--- pkg/amqp-ext/Client/RabbitMqDriver.php | 2 +- pkg/amqp-ext/examples/produce.php | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/amqp-ext/AmqpContext.php b/pkg/amqp-ext/AmqpContext.php index 76a4974ee..6d1f40f06 100644 --- a/pkg/amqp-ext/AmqpContext.php +++ b/pkg/amqp-ext/AmqpContext.php @@ -2,15 +2,15 @@ namespace Enqueue\AmqpExt; -use Enqueue\Psr\Exception; +use Interop\Amqp\AmqpBind as InteropAmqpBind; use Interop\Amqp\AmqpContext as InteropAmqpContext; -use Interop\Amqp\AmqpTopic as InteropAmqpTopic; use Interop\Amqp\AmqpQueue as InteropAmqpQueue; -use Interop\Amqp\AmqpBind as InteropAmqpBind; +use Interop\Amqp\AmqpTopic as InteropAmqpTopic; use Interop\Amqp\Impl\AmqpBind; use Interop\Amqp\Impl\AmqpMessage; use Interop\Amqp\Impl\AmqpQueue; use Interop\Amqp\Impl\AmqpTopic; +use Interop\Queue\Exception; use Interop\Queue\InvalidDestinationException; use Interop\Queue\PsrDestination; use Interop\Queue\PsrTopic; diff --git a/pkg/amqp-ext/Client/RabbitMqDriver.php b/pkg/amqp-ext/Client/RabbitMqDriver.php index 6815bfe59..6c2b5c213 100644 --- a/pkg/amqp-ext/Client/RabbitMqDriver.php +++ b/pkg/amqp-ext/Client/RabbitMqDriver.php @@ -179,7 +179,7 @@ public function setupBroker(LoggerInterface $logger = null) $this->context->declareTopic($delayTopic); $log('Bind processor queue to delay exchange: %s -> %s', $queue->getQueueName(), $delayTopic->getTopicName()); - $this->context->bind(new AmqpBind($delayTopic, $queue , $queue->getQueueName())); + $this->context->bind(new AmqpBind($delayTopic, $queue, $queue->getQueueName())); } } } diff --git a/pkg/amqp-ext/examples/produce.php b/pkg/amqp-ext/examples/produce.php index 2928ed24f..a905e49be 100644 --- a/pkg/amqp-ext/examples/produce.php +++ b/pkg/amqp-ext/examples/produce.php @@ -16,8 +16,8 @@ } use Enqueue\AmqpExt\AmqpConnectionFactory; -use Interop\Amqp\AmqpTopic; use Interop\Amqp\AmqpQueue; +use Interop\Amqp\AmqpTopic; use Interop\Amqp\Impl\AmqpBind; $config = [ From 08fe5ab04af46105bd9a0a62d9f5d7d556c30112 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Wed, 26 Jul 2017 10:48:50 +0300 Subject: [PATCH 13/76] amqp ext interop --- pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php | 5 +++-- .../Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php b/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php index 910ce1d47..ceba5f51c 100644 --- a/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php +++ b/pkg/amqp-ext/Tests/Functional/AmqpCommonUseCasesTest.php @@ -5,6 +5,7 @@ use Enqueue\AmqpExt\AmqpContext; use Enqueue\Test\RabbitmqAmqpExtension; use Enqueue\Test\RabbitmqManagmentExtensionTrait; +use Interop\Amqp\Impl\AmqpBind; use Interop\Amqp\Impl\AmqpMessage; use PHPUnit\Framework\TestCase; @@ -133,7 +134,7 @@ public function testProduceAndReceiveOneMessageSentDirectlyToTopic() $queue = $this->amqpContext->createQueue('amqp_ext.test'); $this->amqpContext->declareQueue($queue); - $this->amqpContext->bind($topic, $queue); + $this->amqpContext->bind(new AmqpBind($topic, $queue)); $message = $this->amqpContext->createMessage(__METHOD__); @@ -209,7 +210,7 @@ public function testPurgeMessagesFromQueue() $producer->send($queue, $message); $producer->send($queue, $message); - $this->amqpContext->purge($queue); + $this->amqpContext->purgeQueue($queue); $this->assertNull($consumer->receive(1)); } diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php index e2191ce2e..be29f1a4f 100644 --- a/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueTest.php @@ -5,6 +5,7 @@ use Enqueue\AmqpExt\AmqpConnectionFactory; use Enqueue\AmqpExt\AmqpContext; use Interop\Amqp\AmqpTopic; +use Interop\Amqp\Impl\AmqpBind; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToTopicAndReceiveFromQueueSpec; @@ -34,7 +35,7 @@ protected function createQueue(PsrContext $context, $queueName) $context->declareQueue($queue); $context->purgeQueue($queue); - $context->bind($context->createTopic($queueName), $queue); + $context->bind(new AmqpBind($context->createTopic($queueName), $queue)); return $queue; } From 2e8315749b2c4c992eda3a630f196d96c74544d1 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Wed, 26 Jul 2017 15:18:56 +0300 Subject: [PATCH 14/76] amqp lib interop --- pkg/amqp-ext/composer.json | 2 +- pkg/amqp-lib/AmqpConnectionFactory.php | 4 +- pkg/amqp-lib/AmqpConsumer.php | 120 +++++++--- pkg/amqp-lib/AmqpContext.php | 198 ++++++++++------- pkg/amqp-lib/AmqpMessage.php | 295 ------------------------- pkg/amqp-lib/AmqpProducer.php | 31 +-- pkg/amqp-lib/AmqpQueue.php | 243 -------------------- pkg/amqp-lib/AmqpTopic.php | 224 ------------------- pkg/amqp-lib/Buffer.php | 2 + pkg/amqp-lib/Tests/AmqpMessageTest.php | 55 ----- pkg/amqp-lib/Tests/AmqpQueueTest.php | 122 ---------- pkg/amqp-lib/Tests/AmqpTopicTest.php | 116 ---------- pkg/amqp-lib/composer.json | 1 + pkg/amqp-lib/examples/consume.php | 52 +++++ pkg/amqp-lib/examples/produce.php | 65 ++++++ 15 files changed, 352 insertions(+), 1178 deletions(-) delete mode 100644 pkg/amqp-lib/AmqpMessage.php delete mode 100644 pkg/amqp-lib/AmqpQueue.php delete mode 100644 pkg/amqp-lib/AmqpTopic.php delete mode 100644 pkg/amqp-lib/Tests/AmqpMessageTest.php delete mode 100644 pkg/amqp-lib/Tests/AmqpQueueTest.php delete mode 100644 pkg/amqp-lib/Tests/AmqpTopicTest.php create mode 100644 pkg/amqp-lib/examples/consume.php create mode 100644 pkg/amqp-lib/examples/produce.php diff --git a/pkg/amqp-ext/composer.json b/pkg/amqp-ext/composer.json index 5b1694d19..0d262df03 100644 --- a/pkg/amqp-ext/composer.json +++ b/pkg/amqp-ext/composer.json @@ -14,6 +14,7 @@ "php": ">=5.6", "ext-amqp": "^1.6", "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/amqp-interop": "^0.5@dev", "psr/log": "^1" }, "require-dev": { @@ -22,7 +23,6 @@ "enqueue/enqueue": "^0.6@dev", "enqueue/null": "^0.6@dev", "queue-interop/queue-spec": "^0.5@dev", - "queue-interop/amqp-interop": "^0.5@dev", "empi89/php-amqp-stubs": "*@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" diff --git a/pkg/amqp-lib/AmqpConnectionFactory.php b/pkg/amqp-lib/AmqpConnectionFactory.php index ac2e31bb1..9c1f02186 100644 --- a/pkg/amqp-lib/AmqpConnectionFactory.php +++ b/pkg/amqp-lib/AmqpConnectionFactory.php @@ -2,14 +2,14 @@ namespace Enqueue\AmqpLib; -use Interop\Queue\PsrConnectionFactory; +use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory; use PhpAmqpLib\Connection\AbstractConnection; use PhpAmqpLib\Connection\AMQPLazyConnection; use PhpAmqpLib\Connection\AMQPLazySocketConnection; use PhpAmqpLib\Connection\AMQPSocketConnection; use PhpAmqpLib\Connection\AMQPStreamConnection; -class AmqpConnectionFactory implements PsrConnectionFactory +class AmqpConnectionFactory implements InteropAmqpConnectionFactory { /** * @var array diff --git a/pkg/amqp-lib/AmqpConsumer.php b/pkg/amqp-lib/AmqpConsumer.php index d73f1e843..fd192f615 100644 --- a/pkg/amqp-lib/AmqpConsumer.php +++ b/pkg/amqp-lib/AmqpConsumer.php @@ -2,16 +2,19 @@ namespace Enqueue\AmqpLib; +use Interop\Amqp\AmqpConsumer as InteropAmqpConsumer; +use Interop\Amqp\AmqpMessage as InteropAmqpMessage; +use Interop\Amqp\AmqpQueue as InteropAmqpQueue; +use Interop\Amqp\Impl\AmqpMessage; use Interop\Queue\Exception; use Interop\Queue\InvalidMessageException; -use Interop\Queue\PsrConsumer; use Interop\Queue\PsrMessage; use PhpAmqpLib\Channel\AMQPChannel; use PhpAmqpLib\Exception\AMQPTimeoutException; use PhpAmqpLib\Message\AMQPMessage as LibAMQPMessage; use PhpAmqpLib\Wire\AMQPTable; -class AmqpConsumer implements PsrConsumer +class AmqpConsumer implements InteropAmqpConsumer { /** * @var AMQPChannel @@ -19,7 +22,7 @@ class AmqpConsumer implements PsrConsumer private $channel; /** - * @var AmqpQueue + * @var InteropAmqpQueue */ private $queue; @@ -39,33 +42,87 @@ class AmqpConsumer implements PsrConsumer private $receiveMethod; /** - * @var AmqpMessage + * @var InteropAmqpMessage */ private $receivedMessage; + /** + * @var int + */ + private $flags; + /** * @var string */ private $consumerTag; /** - * @param AMQPChannel $channel - * @param AmqpQueue $queue - * @param Buffer $buffer - * @param string $receiveMethod + * @param AMQPChannel $channel + * @param InteropAmqpQueue $queue + * @param Buffer $buffer + * @param string $receiveMethod */ - public function __construct(AMQPChannel $channel, AmqpQueue $queue, Buffer $buffer, $receiveMethod) + public function __construct(AMQPChannel $channel, InteropAmqpQueue $queue, Buffer $buffer, $receiveMethod) { $this->channel = $channel; $this->queue = $queue; $this->buffer = $buffer; $this->receiveMethod = $receiveMethod; + $this->flags = self::FLAG_NOPARAM; $this->isInit = false; } /** - * @return AmqpQueue + * {@inheritdoc} + */ + public function setConsumerTag($consumerTag) + { + $this->consumerTag = $consumerTag; + } + + /** + * {@inheritdoc} + */ + public function getConsumerTag() + { + return $this->consumerTag; + } + + /** + * {@inheritdoc} + */ + public function clearFlags() + { + $this->flags = self::FLAG_NOPARAM; + } + + /** + * {@inheritdoc} + */ + public function addFlag($flag) + { + $this->flags |= $flag; + } + + /** + * {@inheritdoc} + */ + public function getFlags() + { + return $this->flags; + } + + /** + * {@inheritdoc} + */ + public function setFlags($flags) + { + $this->flags = $flags; + } + + /** + * @return InteropAmqpQueue */ public function getQueue() { @@ -75,7 +132,7 @@ public function getQueue() /** * {@inheritdoc} * - * @return AmqpMessage|null + * @return InteropAmqpMessage|null */ public function receive($timeout = 0) { @@ -91,32 +148,34 @@ public function receive($timeout = 0) } /** - * @return AmqpMessage|null + * @return InteropAmqpMessage|null */ public function receiveNoWait() { - if ($message = $this->channel->basic_get($this->queue->getQueueName())) { + if ($message = $this->channel->basic_get($this->queue->getQueueName(), !!($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK))) { return $this->convertMessage($message); } } /** - * @param AmqpMessage $message + * @param InteropAmqpMessage $message */ public function acknowledge(PsrMessage $message) { - InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class); + InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); + + var_dump($message->getDeliveryTag()); $this->channel->basic_ack($message->getDeliveryTag()); } /** - * @param AmqpMessage $message - * @param bool $requeue + * @param InteropAmqpMessage $message + * @param bool $requeue */ public function reject(PsrMessage $message, $requeue = false) { - InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class); + InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); $this->channel->basic_reject($message->getDeliveryTag(), $requeue); } @@ -124,7 +183,7 @@ public function reject(PsrMessage $message, $requeue = false) /** * @param LibAMQPMessage $amqpMessage * - * @return AmqpMessage + * @return InteropAmqpMessage */ private function convertMessage(LibAMQPMessage $amqpMessage) { @@ -147,7 +206,7 @@ private function convertMessage(LibAMQPMessage $amqpMessage) /** * @param int $timeout * - * @return AmqpMessage|null + * @return InteropAmqpMessage|null */ private function receiveBasicGet($timeout) { @@ -165,20 +224,20 @@ private function receiveBasicGet($timeout) /** * @param int $timeout * - * @return AmqpMessage|null + * @return InteropAmqpMessage|null */ private function receiveBasicConsume($timeout) { if (false === $this->isInit) { $callback = function (LibAMQPMessage $message) { $receivedMessage = $this->convertMessage($message); - $consumerTag = $message->delivery_info['consumer_tag']; + $receivedMessage->setConsumerTag($message->delivery_info['consumer_tag']); - if ($this->consumerTag === $consumerTag) { + if ($this->consumerTag === $receivedMessage->getConsumerTag()) { $this->receivedMessage = $receivedMessage; } else { // not our message, put it to buffer and continue. - $this->buffer->push($consumerTag, $receivedMessage); + $this->buffer->push($receivedMessage->getConsumerTag(), $receivedMessage); } }; @@ -186,11 +245,11 @@ private function receiveBasicConsume($timeout) $consumerTag = $this->channel->basic_consume( $this->queue->getQueueName(), - $this->queue->getConsumerTag(), - $this->queue->isNoLocal(), - $this->queue->isNoAck(), - $this->queue->isExclusive(), - $this->queue->isNoWait(), + $this->getConsumerTag() ?: $this->getQueue()->getConsumerTag(), + !!($this->getFlags() & InteropAmqpConsumer::FLAG_NOLOCAL), + !!($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK), + !!($this->getFlags() & InteropAmqpConsumer::FLAG_EXCLUSIVE), + !!($this->getFlags() & InteropAmqpConsumer::FLAG_NOWAIT), $callback ); @@ -210,8 +269,11 @@ private function receiveBasicConsume($timeout) $this->receivedMessage = null; try { + echo 'here', PHP_EOL; $this->channel->wait(null, false, $timeout); + echo 'here1', PHP_EOL; } catch (AMQPTimeoutException $e) { + echo 'here2', PHP_EOL; } return $this->receivedMessage; diff --git a/pkg/amqp-lib/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php index 168766ad5..2ab5eb751 100644 --- a/pkg/amqp-lib/AmqpContext.php +++ b/pkg/amqp-lib/AmqpContext.php @@ -2,16 +2,23 @@ namespace Enqueue\AmqpLib; +use Interop\Amqp\AmqpBind as InteropAmqpBind; +use Interop\Amqp\AmqpMessage as InteropAmqpMessage; +use Interop\Amqp\AmqpQueue as InteropAmqpQueue; +use Interop\Amqp\AmqpTopic as InteropAmqpTopic; +use Interop\Amqp\AmqpContext as InteropAmqpContext; +use Interop\Amqp\Impl\AmqpBind; +use Interop\Amqp\Impl\AmqpMessage; +use Interop\Amqp\Impl\AmqpQueue; +use Interop\Amqp\Impl\AmqpTopic; use Interop\Queue\Exception; use Interop\Queue\InvalidDestinationException; -use Interop\Queue\PsrContext; use Interop\Queue\PsrDestination; -use Interop\Queue\PsrQueue; use Interop\Queue\PsrTopic; use PhpAmqpLib\Channel\AMQPChannel; use PhpAmqpLib\Connection\AbstractConnection; -class AmqpContext implements PsrContext +class AmqpContext implements InteropAmqpContext { /** * @var AbstractConnection @@ -49,7 +56,7 @@ public function __construct(AbstractConnection $connection, $receiveMethod) * @param array $properties * @param array $headers * - * @return AmqpMessage + * @return InteropAmqpMessage */ public function createMessage($body = '', array $properties = [], array $headers = []) { @@ -59,7 +66,7 @@ public function createMessage($body = '', array $properties = [], array $headers /** * @param string $name * - * @return AmqpQueue + * @return InteropAmqpQueue */ public function createQueue($name) { @@ -69,7 +76,7 @@ public function createQueue($name) /** * @param string $name * - * @return AmqpTopic + * @return InteropAmqpTopic */ public function createTopic($name) { @@ -84,13 +91,13 @@ public function createTopic($name) public function createConsumer(PsrDestination $destination) { $destination instanceof PsrTopic - ? InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class) - : InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class) + ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class) + : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class) ; if ($destination instanceof AmqpTopic) { $queue = $this->createTemporaryQueue(); - $this->bind($destination, $queue); + $this->bind(new AmqpBind($destination, $queue, $queue->getQueueName())); return new AmqpConsumer($this->getChannel(), $queue, $this->buffer, $this->receiveMethod); } @@ -107,12 +114,12 @@ public function createProducer() } /** - * @return AmqpQueue + * @return InteropAmqpQueue */ public function createTemporaryQueue() { $queue = $this->createQueue(null); - $queue->setExclusive(true); + $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE); $this->declareQueue($queue); @@ -120,109 +127,148 @@ public function createTemporaryQueue() } /** - * @param AmqpTopic $destination + * {@inheritdoc} */ - public function declareTopic(PsrDestination $destination) + public function declareTopic(InteropAmqpTopic $topic) { - InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class); - $this->getChannel()->exchange_declare( - $destination->getTopicName(), - $destination->getType(), - $destination->isPassive(), - $destination->isDurable(), - $destination->isAutoDelete(), - $destination->isInternal(), - $destination->isNoWait(), - $destination->getArguments(), - $destination->getTicket() + $topic->getTopicName(), + $topic->getType(), + !!($topic->getFlags() & InteropAmqpTopic::FLAG_PASSIVE), + !!($topic->getFlags() & InteropAmqpTopic::FLAG_DURABLE), + !!($topic->getFlags() & InteropAmqpTopic::FLAG_AUTODELETE), + !!($topic->getFlags() & InteropAmqpTopic::FLAG_INTERNAL), + !!($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT), + $topic->getArguments() ); } /** - * @param AmqpQueue $destination + * {@inheritdoc} */ - public function declareQueue(PsrDestination $destination) + public function deleteTopic(InteropAmqpTopic $topic) { - InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class); + $this->getChannel()->exchange_delete( + $topic->getTopicName(), + !!($topic->getFlags() & InteropAmqpTopic::FLAG_IFUNUSED), + !!($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT) + ); + } - $this->getChannel()->queue_declare( - $destination->getQueueName(), - $destination->isPassive(), - $destination->isDurable(), - $destination->isExclusive(), - $destination->isAutoDelete(), - $destination->isNoWait(), - $destination->getArguments(), - $destination->getTicket() + /** + * {@inheritdoc} + */ + public function declareQueue(InteropAmqpQueue $queue) + { + return $this->getChannel()->queue_declare( + $queue->getQueueName(), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_PASSIVE), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_DURABLE), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_EXCLUSIVE), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_AUTODELETE), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT), + $queue->getArguments() ); } /** - * @param AmqpTopic|AmqpQueue $source - * @param AmqpTopic|AmqpQueue $target - * - * @throws Exception + * {@inheritdoc} */ - public function bind(PsrDestination $source, PsrDestination $target) + public function deleteQueue(InteropAmqpQueue $queue) { - $source instanceof PsrTopic - ? InvalidDestinationException::assertDestinationInstanceOf($source, AmqpTopic::class) - : InvalidDestinationException::assertDestinationInstanceOf($source, AmqpQueue::class) - ; + $this->getChannel()->queue_delete( + $queue->getQueueName(), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_IFUNUSED), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_IFEMPTY), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT) + ); + } - $target instanceof PsrTopic - ? InvalidDestinationException::assertDestinationInstanceOf($target, AmqpTopic::class) - : InvalidDestinationException::assertDestinationInstanceOf($target, AmqpQueue::class) - ; + /** + * {@inheritdoc} + */ + public function purgeQueue(InteropAmqpQueue $queue) + { + $this->getChannel()->queue_purge( + $queue->getQueueName(), + !!($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT) + ); + } - if ($source instanceof AmqpQueue && $target instanceof AmqpQueue) { + /** + * {@inheritdoc} + */ + public function bind(InteropAmqpBind $bind) + { + if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic'); } // bind exchange to exchange - if ($source instanceof AmqpTopic && $target instanceof AmqpTopic) { + if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { $this->getChannel()->exchange_bind( - $target->getTopicName(), - $source->getTopicName(), - $source->getRoutingKey(), - $source->isNowait(), - $source->getArguments(), - $source->getTicket() + $bind->getTarget()->getTopicName(), + $bind->getSource()->getTopicName(), + $bind->getRoutingKey(), + !!($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + $bind->getArguments() ); // bind queue to exchange - } elseif ($source instanceof AmqpQueue) { + } elseif ($bind->getSource() instanceof InteropAmqpQueue) { $this->getChannel()->queue_bind( - $source->getQueueName(), - $target->getTopicName(), - $target->getRoutingKey(), - $target->isNowait(), - $target->getArguments(), - $target->getTicket() + $bind->getSource()->getQueueName(), + $bind->getTarget()->getTopicName(), + $bind->getRoutingKey(), + !!($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + $bind->getArguments() ); // bind exchange to queue } else { $this->getChannel()->queue_bind( - $target->getQueueName(), - $source->getTopicName(), - $source->getRoutingKey(), - $source->isNowait(), - $source->getArguments(), - $source->getTicket() + $bind->getTarget()->getQueueName(), + $bind->getSource()->getTopicName(), + $bind->getRoutingKey(), + !!($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + $bind->getArguments() ); } } /** - * Purge all messages from the given queue. - * - * @param PsrQueue $queue + * {@inheritdoc} */ - public function purge(PsrQueue $queue) + public function unbind(InteropAmqpBind $bind) { - InvalidDestinationException::assertDestinationInstanceOf($queue, AmqpQueue::class); + if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { + throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic'); + } - $this->getChannel()->queue_purge($queue->getQueueName()); + // bind exchange to exchange + if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { + $this->getChannel()->exchange_unbind( + $bind->getTarget()->getTopicName(), + $bind->getSource()->getTopicName(), + $bind->getRoutingKey(), + !!($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + $bind->getArguments() + ); + // bind queue to exchange + } elseif ($bind->getSource() instanceof InteropAmqpQueue) { + $this->getChannel()->queue_unbind( + $bind->getSource()->getQueueName(), + $bind->getTarget()->getTopicName(), + $bind->getRoutingKey(), + $bind->getArguments() + ); + // bind exchange to queue + } else { + $this->getChannel()->queue_unbind( + $bind->getTarget()->getQueueName(), + $bind->getSource()->getTopicName(), + $bind->getRoutingKey(), + $bind->getArguments() + ); + } } public function close() diff --git a/pkg/amqp-lib/AmqpMessage.php b/pkg/amqp-lib/AmqpMessage.php deleted file mode 100644 index f391d7364..000000000 --- a/pkg/amqp-lib/AmqpMessage.php +++ /dev/null @@ -1,295 +0,0 @@ -body = $body; - $this->properties = $properties; - $this->headers = $headers; - $this->redelivered = false; - } - - /** - * @return string - */ - public function getBody() - { - return $this->body; - } - - /** - * @param string $body - */ - public function setBody($body) - { - $this->body = $body; - } - - /** - * @param array $properties - */ - public function setProperties(array $properties) - { - $this->properties = $properties; - } - - /** - * @return array - */ - public function getProperties() - { - return $this->properties; - } - - /** - * @param string $name - * @param mixed $value - */ - public function setProperty($name, $value) - { - $this->properties[$name] = $value; - } - - /** - * @param string $name - * @param mixed $default - * - * @return mixed - */ - public function getProperty($name, $default = null) - { - return array_key_exists($name, $this->properties) ? $this->properties[$name] : $default; - } - - /** - * @param array $headers - */ - public function setHeaders(array $headers) - { - $this->headers = $headers; - } - - /** - * @return array - */ - public function getHeaders() - { - return $this->headers; - } - - /** - * @param string $name - * @param mixed $value - */ - public function setHeader($name, $value) - { - $this->headers[$name] = $value; - } - - /** - * @param string $name - * @param mixed $default - * - * @return mixed - */ - public function getHeader($name, $default = null) - { - return array_key_exists($name, $this->headers) ? $this->headers[$name] : $default; - } - - /** - * @param bool $redelivered - */ - public function setRedelivered($redelivered) - { - $this->redelivered = (bool) $redelivered; - } - - /** - * @return bool - */ - public function isRedelivered() - { - return $this->redelivered; - } - - /** - * @param string $correlationId - */ - public function setCorrelationId($correlationId) - { - $this->setHeader('correlation_id', $correlationId); - } - - /** - * @return string - */ - public function getCorrelationId() - { - return $this->getHeader('correlation_id'); - } - - /** - * @param string $messageId - */ - public function setMessageId($messageId) - { - $this->setHeader('message_id', $messageId); - } - - /** - * @return string - */ - public function getMessageId() - { - return $this->getHeader('message_id'); - } - - /** - * @return int - */ - public function getTimestamp() - { - $value = $this->getHeader('timestamp'); - - return $value === null ? null : (int) $value; - } - - /** - * @param int $timestamp - */ - public function setTimestamp($timestamp) - { - $this->setHeader('timestamp', $timestamp); - } - - /** - * @param string|null $replyTo - */ - public function setReplyTo($replyTo) - { - $this->setHeader('reply_to', $replyTo); - } - - /** - * @return string|null - */ - public function getReplyTo() - { - return $this->getHeader('reply_to'); - } - - /** - * @return string - */ - public function getDeliveryTag() - { - return $this->deliveryTag; - } - - /** - * @param string $deliveryTag - */ - public function setDeliveryTag($deliveryTag) - { - $this->deliveryTag = $deliveryTag; - } - - /** - * @return bool - */ - public function isMandatory() - { - return $this->mandatory; - } - - /** - * @param int $mandatory - */ - public function setMandatory($mandatory) - { - $this->mandatory = $mandatory; - } - - /** - * @return bool - */ - public function isImmediate() - { - return $this->immediate; - } - - /** - * @param bool $immediate - */ - public function setImmediate($immediate) - { - $this->immediate = $immediate; - } - - /** - * @return int - */ - public function getTicket() - { - return $this->ticket; - } - - /** - * @param int $ticket - */ - public function setTicket($ticket) - { - $this->ticket = $ticket; - } -} diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php index b5cf61805..8d83644e3 100644 --- a/pkg/amqp-lib/AmqpProducer.php +++ b/pkg/amqp-lib/AmqpProducer.php @@ -2,17 +2,20 @@ namespace Enqueue\AmqpLib; +use Interop\Amqp\AmqpMessage as InteropAmqpMessage; +use Interop\Amqp\AmqpProducer as InteropAmqpProducer; +use Interop\Amqp\AmqpQueue as InteropAmqpQueue; +use Interop\Amqp\AmqpTopic as InteropAmqpTopic; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; use Interop\Queue\PsrMessage; -use Interop\Queue\PsrProducer; use Interop\Queue\PsrTopic; use PhpAmqpLib\Channel\AMQPChannel; use PhpAmqpLib\Message\AMQPMessage as LibAMQPMessage; use PhpAmqpLib\Wire\AMQPTable; -class AmqpProducer implements PsrProducer +class AmqpProducer implements InteropAmqpProducer { /** * @var AMQPChannel @@ -28,17 +31,17 @@ public function __construct(AMQPChannel $channel) } /** - * @param AmqpTopic|AmqpQueue $destination - * @param AmqpMessage $message + * @param InteropAmqpTopic|InteropAmqpQueue $destination + * @param InteropAmqpMessage $message */ public function send(PsrDestination $destination, PsrMessage $message) { $destination instanceof PsrTopic - ? InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpTopic::class) - : InvalidDestinationException::assertDestinationInstanceOf($destination, AmqpQueue::class) + ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class) + : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class) ; - InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class); + InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); $amqpProperties = $message->getHeaders(); @@ -48,23 +51,21 @@ public function send(PsrDestination $destination, PsrMessage $message) $amqpMessage = new LibAMQPMessage($message->getBody(), $amqpProperties); - if ($destination instanceof AmqpTopic) { + if ($destination instanceof InteropAmqpTopic) { $this->channel->basic_publish( $amqpMessage, $destination->getTopicName(), - $destination->getRoutingKey(), - $message->isMandatory(), - $message->isImmediate(), - $message->getTicket() + $message->getRoutingKey(), + !!($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY), + !!($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE) ); } else { $this->channel->basic_publish( $amqpMessage, '', $destination->getQueueName(), - $message->isMandatory(), - $message->isImmediate(), - $message->getTicket() + !!($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY), + !!($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE) ); } } diff --git a/pkg/amqp-lib/AmqpQueue.php b/pkg/amqp-lib/AmqpQueue.php deleted file mode 100644 index 5c6551c73..000000000 --- a/pkg/amqp-lib/AmqpQueue.php +++ /dev/null @@ -1,243 +0,0 @@ -name = $name; - $this->passive = false; - $this->durable = false; - $this->exclusive = false; - $this->autoDelete = true; - $this->noWait = false; - $this->noLocal = false; - $this->noAck = false; - } - - /** - * @return string - */ - public function getQueueName() - { - return $this->name; - } - - /** - * @return bool - */ - public function isPassive() - { - return $this->passive; - } - - /** - * @param bool $passive - */ - public function setPassive($passive) - { - $this->passive = (bool) $passive; - } - - /** - * @return bool - */ - public function isDurable() - { - return $this->durable; - } - - /** - * @param bool $durable - */ - public function setDurable($durable) - { - $this->durable = (bool) $durable; - } - - /** - * @return bool - */ - public function isExclusive() - { - return $this->exclusive; - } - - /** - * @param bool $exclusive - */ - public function setExclusive($exclusive) - { - $this->exclusive = (bool) $exclusive; - } - - /** - * @return bool - */ - public function isAutoDelete() - { - return $this->autoDelete; - } - - /** - * @param bool $autoDelete - */ - public function setAutoDelete($autoDelete) - { - $this->autoDelete = (bool) $autoDelete; - } - - /** - * @return bool - */ - public function isNoWait() - { - return $this->noWait; - } - - /** - * @param bool $noWait - */ - public function setNoWait($noWait) - { - $this->noWait = (bool) $noWait; - } - - /** - * @return array|null - */ - public function getArguments() - { - return $this->arguments; - } - - /** - * @param array|null $arguments - */ - public function setArguments(array $arguments = null) - { - $this->arguments = $arguments; - } - - /** - * @return int - */ - public function getTicket() - { - return $this->ticket; - } - - /** - * @param int $ticket - */ - public function setTicket($ticket) - { - $this->ticket = $ticket; - } - - /** - * @return string - */ - public function getConsumerTag() - { - return $this->consumerTag; - } - - /** - * @param string $consumerTag - */ - public function setConsumerTag($consumerTag) - { - $this->consumerTag = $consumerTag; - } - - /** - * @return bool - */ - public function isNoLocal() - { - return $this->noLocal; - } - - /** - * @param bool $noLocal - */ - public function setNoLocal($noLocal) - { - $this->noLocal = $noLocal; - } - - /** - * @return bool - */ - public function isNoAck() - { - return $this->noAck; - } - - /** - * @param bool $noAck - */ - public function setNoAck($noAck) - { - $this->noAck = $noAck; - } -} diff --git a/pkg/amqp-lib/AmqpTopic.php b/pkg/amqp-lib/AmqpTopic.php deleted file mode 100644 index a1d029853..000000000 --- a/pkg/amqp-lib/AmqpTopic.php +++ /dev/null @@ -1,224 +0,0 @@ -name = $name; - $this->type = 'direct'; - $this->passive = false; - $this->durable = false; - $this->autoDelete = true; - $this->internal = false; - $this->noWait = false; - } - - /** - * @return string - */ - public function getTopicName() - { - return $this->name; - } - - /** - * @return string - */ - public function getType() - { - return $this->type; - } - - /** - * @param string $type - */ - public function setType($type) - { - $this->type = $type; - } - - /** - * @return bool - */ - public function isPassive() - { - return $this->passive; - } - - /** - * @param bool $passive - */ - public function setPassive($passive) - { - $this->passive = (bool) $passive; - } - - /** - * @return bool - */ - public function isDurable() - { - return $this->durable; - } - - /** - * @param bool $durable - */ - public function setDurable($durable) - { - $this->durable = (bool) $durable; - } - - /** - * @return bool - */ - public function isAutoDelete() - { - return $this->autoDelete; - } - - /** - * @param bool $autoDelete - */ - public function setAutoDelete($autoDelete) - { - $this->autoDelete = (bool) $autoDelete; - } - - /** - * @return bool - */ - public function isInternal() - { - return $this->internal; - } - - /** - * @param bool $internal - */ - public function setInternal($internal) - { - $this->internal = (bool) $internal; - } - - /** - * @return bool - */ - public function isNoWait() - { - return $this->noWait; - } - - /** - * @param bool $noWait - */ - public function setNoWait($noWait) - { - $this->noWait = (bool) $noWait; - } - - /** - * @return array|null - */ - public function getArguments() - { - return $this->arguments; - } - - /** - * @param array|null $arguments - */ - public function setArguments(array $arguments = null) - { - $this->arguments = $arguments; - } - - /** - * @return int - */ - public function getTicket() - { - return $this->ticket; - } - - /** - * @param int $ticket - */ - public function setTicket($ticket) - { - $this->ticket = $ticket; - } - - /** - * @return string - */ - public function getRoutingKey() - { - return $this->routingKey; - } - - /** - * @param string $routingKey - */ - public function setRoutingKey($routingKey) - { - $this->routingKey = $routingKey; - } -} diff --git a/pkg/amqp-lib/Buffer.php b/pkg/amqp-lib/Buffer.php index 55c06f619..27732806e 100644 --- a/pkg/amqp-lib/Buffer.php +++ b/pkg/amqp-lib/Buffer.php @@ -2,6 +2,8 @@ namespace Enqueue\AmqpLib; +use Interop\Amqp\AmqpMessage; + class Buffer { /** diff --git a/pkg/amqp-lib/Tests/AmqpMessageTest.php b/pkg/amqp-lib/Tests/AmqpMessageTest.php deleted file mode 100644 index 7c927a2cf..000000000 --- a/pkg/amqp-lib/Tests/AmqpMessageTest.php +++ /dev/null @@ -1,55 +0,0 @@ -setDeliveryTag('theDeliveryTag'); - - $this->assertSame('theDeliveryTag', $message->getDeliveryTag()); - } - - public function testShouldAllowGetPreviouslySetMandatory() - { - $topic = new AmqpMessage('aName'); - - $topic->setMandatory(false); - $this->assertFalse($topic->isMandatory()); - - $topic->setMandatory(true); - $this->assertTrue($topic->isMandatory()); - } - - public function testShouldAllowGetPreviouslySetImmediate() - { - $topic = new AmqpMessage('aName'); - - $topic->setImmediate(false); - $this->assertFalse($topic->isImmediate()); - - $topic->setImmediate(true); - $this->assertTrue($topic->isImmediate()); - } - - public function testShouldAllowGetPreviouslySetTicket() - { - $topic = new AmqpMessage('aName'); - - //guard - $this->assertSame(null, $topic->getTicket()); - - $topic->setTicket('ticket'); - - $this->assertSame('ticket', $topic->getTicket()); - } -} diff --git a/pkg/amqp-lib/Tests/AmqpQueueTest.php b/pkg/amqp-lib/Tests/AmqpQueueTest.php deleted file mode 100644 index 34aceeba7..000000000 --- a/pkg/amqp-lib/Tests/AmqpQueueTest.php +++ /dev/null @@ -1,122 +0,0 @@ -setPassive(false); - $this->assertFalse($topic->isPassive()); - - $topic->setPassive(true); - $this->assertTrue($topic->isPassive()); - } - - public function testShouldAllowGetPreviouslySetDurable() - { - $topic = new AmqpQueue('aName'); - - $topic->setDurable(false); - $this->assertFalse($topic->isDurable()); - - $topic->setDurable(true); - $this->assertTrue($topic->isDurable()); - } - - public function testShouldAllowGetPreviouslySetExclusive() - { - $topic = new AmqpQueue('aName'); - - $topic->setExclusive(false); - $this->assertFalse($topic->isExclusive()); - - $topic->setExclusive(true); - $this->assertTrue($topic->isExclusive()); - } - - public function testShouldAllowGetPreviouslySetAutoDelete() - { - $topic = new AmqpQueue('aName'); - - $topic->setAutoDelete(false); - $this->assertFalse($topic->isAutoDelete()); - - $topic->setAutoDelete(true); - $this->assertTrue($topic->isAutoDelete()); - } - - public function testShouldAllowGetPreviouslySetNoWait() - { - $topic = new AmqpQueue('aName'); - - $topic->setNoWait(false); - $this->assertFalse($topic->isNoWait()); - - $topic->setNoWait(true); - $this->assertTrue($topic->isNoWait()); - } - - public function testShouldAllowGetPreviouslySetArguments() - { - $queue = new AmqpQueue('aName'); - - $queue->setArguments(['foo' => 'fooVal', 'bar' => 'barVal']); - - $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $queue->getArguments()); - } - - public function testShouldAllowGetPreviouslySetTicket() - { - $topic = new AmqpQueue('aName'); - - //guard - $this->assertSame(null, $topic->getTicket()); - - $topic->setTicket('ticket'); - - $this->assertSame('ticket', $topic->getTicket()); - } - - public function testShouldAllowGetPreviouslySetConsumerTag() - { - $topic = new AmqpQueue('aName'); - - //guard - $this->assertSame(null, $topic->getConsumerTag()); - - $topic->setConsumerTag('consumer-tag'); - - $this->assertSame('consumer-tag', $topic->getConsumerTag()); - } - - public function testShouldAllowGetPreviouslySetNoLocal() - { - $topic = new AmqpQueue('aName'); - - $topic->setNoLocal(false); - $this->assertFalse($topic->isNoLocal()); - - $topic->setNoLocal(true); - $this->assertTrue($topic->isNoLocal()); - } - - public function testShouldAllowGetPreviouslySetNoAck() - { - $topic = new AmqpQueue('aName'); - - $topic->setNoAck(false); - $this->assertFalse($topic->isNoAck()); - - $topic->setNoAck(true); - $this->assertTrue($topic->isNoAck()); - } -} diff --git a/pkg/amqp-lib/Tests/AmqpTopicTest.php b/pkg/amqp-lib/Tests/AmqpTopicTest.php deleted file mode 100644 index 2e4649639..000000000 --- a/pkg/amqp-lib/Tests/AmqpTopicTest.php +++ /dev/null @@ -1,116 +0,0 @@ -assertSame('direct', $topic->getType()); - } - - public function testShouldAllowGetPreviouslySetType() - { - $topic = new AmqpTopic('aName'); - - $topic->setType('fanout'); - - $this->assertSame('fanout', $topic->getType()); - } - - public function testShouldAllowGetPreviouslySetPassive() - { - $topic = new AmqpTopic('aName'); - - $topic->setPassive(false); - $this->assertFalse($topic->isPassive()); - - $topic->setPassive(true); - $this->assertTrue($topic->isPassive()); - } - - public function testShouldAllowGetPreviouslySetDurable() - { - $topic = new AmqpTopic('aName'); - - $topic->setDurable(false); - $this->assertFalse($topic->isDurable()); - - $topic->setDurable(true); - $this->assertTrue($topic->isDurable()); - } - - public function testShouldAllowGetPreviouslySetAutoDelete() - { - $topic = new AmqpTopic('aName'); - - $topic->setAutoDelete(false); - $this->assertFalse($topic->isAutoDelete()); - - $topic->setAutoDelete(true); - $this->assertTrue($topic->isAutoDelete()); - } - - public function testShouldAllowGetPreviouslySetInternal() - { - $topic = new AmqpTopic('aName'); - - $topic->setInternal(false); - $this->assertFalse($topic->isInternal()); - - $topic->setInternal(true); - $this->assertTrue($topic->isInternal()); - } - - public function testShouldAllowGetPreviouslySetNoWait() - { - $topic = new AmqpTopic('aName'); - - $topic->setNoWait(false); - $this->assertFalse($topic->isNoWait()); - - $topic->setNoWait(true); - $this->assertTrue($topic->isNoWait()); - } - - public function testShouldAllowGetPreviouslySetArguments() - { - $topic = new AmqpTopic('aName'); - - $topic->setArguments(['foo' => 'fooVal', 'bar' => 'barVal']); - - $this->assertSame(['foo' => 'fooVal', 'bar' => 'barVal'], $topic->getArguments()); - } - - public function testShouldAllowGetPreviouslySetTicket() - { - $topic = new AmqpTopic('aName'); - - //guard - $this->assertSame(null, $topic->getTicket()); - - $topic->setTicket('ticket'); - - $this->assertSame('ticket', $topic->getTicket()); - } - - public function testShouldAllowGetPreviouslySetRoutingKey() - { - $topic = new AmqpTopic('aName'); - - //guard - $this->assertSame(null, $topic->getRoutingKey()); - - $topic->setRoutingKey('theRoutingKey'); - - $this->assertSame('theRoutingKey', $topic->getRoutingKey()); - } -} diff --git a/pkg/amqp-lib/composer.json b/pkg/amqp-lib/composer.json index 16c83929f..126b17d37 100644 --- a/pkg/amqp-lib/composer.json +++ b/pkg/amqp-lib/composer.json @@ -14,6 +14,7 @@ "php": ">=5.6", "php-amqplib/php-amqplib": "^2.7@dev", "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/amqp-interop": "^0.5@dev", "psr/log": "^1" }, "require-dev": { diff --git a/pkg/amqp-lib/examples/consume.php b/pkg/amqp-lib/examples/consume.php new file mode 100644 index 000000000..dea443d3e --- /dev/null +++ b/pkg/amqp-lib/examples/consume.php @@ -0,0 +1,52 @@ + getenv('SYMFONY__RABBITMQ__HOST'), + 'port' => getenv('SYMFONY__RABBITMQ__AMQP__PORT'), + 'user' => getenv('SYMFONY__RABBITMQ__USER'), + 'pass' => getenv('SYMFONY__RABBITMQ__PASSWORD'), + 'vhost' => getenv('SYMFONY__RABBITMQ__VHOST'), + 'receive_method' => 'basic_consume', +]; + +$factory = new AmqpConnectionFactory($config); +$context = $factory->createContext(); + +$queue = $context->createQueue('foo'); +$fooConsumer = $context->createConsumer($queue); + +$queue = $context->createQueue('bar'); +$barConsumer = $context->createConsumer($queue); +//$barConsumer->addFlag(\Interop\Amqp\AmqpConsumer::FLAG_NOACK); + +$consumers = [$fooConsumer, $barConsumer]; + +$consumer = $consumers[rand(0, 1)]; + +while (true) { + if ($m = $consumer->receive(0.100)) { + echo $m->getBody(), PHP_EOL; + $consumer->acknowledge($m); + } + + $consumer = $consumers[rand(0, 1)]; +} + +echo 'Done'."\n"; diff --git a/pkg/amqp-lib/examples/produce.php b/pkg/amqp-lib/examples/produce.php new file mode 100644 index 000000000..4f9a83192 --- /dev/null +++ b/pkg/amqp-lib/examples/produce.php @@ -0,0 +1,65 @@ + getenv('SYMFONY__RABBITMQ__HOST'), + 'port' => getenv('SYMFONY__RABBITMQ__AMQP__PORT'), + 'user' => getenv('SYMFONY__RABBITMQ__USER'), + 'pass' => getenv('SYMFONY__RABBITMQ__PASSWORD'), + 'vhost' => getenv('SYMFONY__RABBITMQ__VHOST'), +]; + +$factory = new AmqpConnectionFactory($config); +$context = $factory->createContext(); + +$topic = $context->createTopic('test.amqp.ext'); +$topic->addFlag(AmqpTopic::FLAG_DURABLE); +$topic->setType(AmqpTopic::TYPE_FANOUT); +//$topic->setArguments(['alternate-exchange' => 'foo']); + +$context->deleteTopic($topic); +$context->declareTopic($topic); + +$fooQueue = $context->createQueue('foo'); +$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE); + +$context->deleteQueue($fooQueue); +$context->declareQueue($fooQueue); + +$context->bind(new AmqpBind($topic, $fooQueue)); + +$barQueue = $context->createQueue('bar'); +$barQueue->addFlag(AmqpQueue::FLAG_DURABLE); + +$context->deleteQueue($barQueue); +$context->declareQueue($barQueue); + +$context->bind(new AmqpBind($topic, $barQueue)); + +$message = $context->createMessage('Hello Bar!'); + +while (true) { + $context->createProducer()->send($fooQueue, $message); + $context->createProducer()->send($barQueue, $message); +} + +echo 'Done'."\n"; From a8a75f9442637e2be22912287d996da4dd8bc615 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Thu, 27 Jul 2017 13:47:34 +0300 Subject: [PATCH 15/76] fix concurrent consumption --- pkg/amqp-lib/AmqpConsumer.php | 51 ++++++++++++++++--------------- pkg/amqp-lib/AmqpContext.php | 1 + pkg/amqp-lib/examples/consume.php | 3 +- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/pkg/amqp-lib/AmqpConsumer.php b/pkg/amqp-lib/AmqpConsumer.php index fd192f615..055736f64 100644 --- a/pkg/amqp-lib/AmqpConsumer.php +++ b/pkg/amqp-lib/AmqpConsumer.php @@ -41,11 +41,6 @@ class AmqpConsumer implements InteropAmqpConsumer */ private $receiveMethod; - /** - * @var InteropAmqpMessage - */ - private $receivedMessage; - /** * @var int */ @@ -164,8 +159,6 @@ public function acknowledge(PsrMessage $message) { InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); - var_dump($message->getDeliveryTag()); - $this->channel->basic_ack($message->getDeliveryTag()); } @@ -233,16 +226,9 @@ private function receiveBasicConsume($timeout) $receivedMessage = $this->convertMessage($message); $receivedMessage->setConsumerTag($message->delivery_info['consumer_tag']); - if ($this->consumerTag === $receivedMessage->getConsumerTag()) { - $this->receivedMessage = $receivedMessage; - } else { - // not our message, put it to buffer and continue. - $this->buffer->push($receivedMessage->getConsumerTag(), $receivedMessage); - } + $this->buffer->push($receivedMessage->getConsumerTag(), $receivedMessage); }; - $this->channel->basic_qos(0, 1, false); - $consumerTag = $this->channel->basic_consume( $this->queue->getQueueName(), $this->getConsumerTag() ?: $this->getQueue()->getConsumerTag(), @@ -253,7 +239,7 @@ private function receiveBasicConsume($timeout) $callback ); - $this->consumerTag = $consumerTag ?: $this->queue->getConsumerTag(); + $this->consumerTag = $consumerTag ?: $this->getQueue()->getConsumerTag(); if (empty($this->consumerTag)) { throw new Exception('Got empty consumer tag'); @@ -266,16 +252,31 @@ private function receiveBasicConsume($timeout) return $message; } - $this->receivedMessage = null; - try { - echo 'here', PHP_EOL; - $this->channel->wait(null, false, $timeout); - echo 'here1', PHP_EOL; - } catch (AMQPTimeoutException $e) { - echo 'here2', PHP_EOL; - } + while (true) { + $start = microtime(true); + + $this->channel->wait(null, false, $timeout / 1000); - return $this->receivedMessage; + if ($message = $this->buffer->pop($this->consumerTag)) { + return $message; + } + + // is here when consumed message is not for this consumer + + // as timeout is infinite have to continue consumption, but it can overflow message buffer + if ($timeout <= 0) { + continue; + } + + // compute remaining timeout and continue until time is up + $stop = microtime(true); + $timeout -= ($stop - $start) * 1000; + + if ($timeout <= 0) { + break; + } + } + } catch (AMQPTimeoutException $e) {} } } diff --git a/pkg/amqp-lib/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php index 2ab5eb751..b380264a8 100644 --- a/pkg/amqp-lib/AmqpContext.php +++ b/pkg/amqp-lib/AmqpContext.php @@ -285,6 +285,7 @@ private function getChannel() { if (null === $this->channel) { $this->channel = $this->connection->channel(); + $this->channel->basic_qos(0, 1, false); } return $this->channel; diff --git a/pkg/amqp-lib/examples/consume.php b/pkg/amqp-lib/examples/consume.php index dea443d3e..9af598bc5 100644 --- a/pkg/amqp-lib/examples/consume.php +++ b/pkg/amqp-lib/examples/consume.php @@ -34,14 +34,13 @@ $queue = $context->createQueue('bar'); $barConsumer = $context->createConsumer($queue); -//$barConsumer->addFlag(\Interop\Amqp\AmqpConsumer::FLAG_NOACK); $consumers = [$fooConsumer, $barConsumer]; $consumer = $consumers[rand(0, 1)]; while (true) { - if ($m = $consumer->receive(0.100)) { + if ($m = $consumer->receive(100)) { echo $m->getBody(), PHP_EOL; $consumer->acknowledge($m); } From a653fa54d875817b3033b26164e004c0eccd40c1 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Thu, 27 Jul 2017 15:51:24 +0300 Subject: [PATCH 16/76] amqp lib interop --- pkg/amqp-lib/Tests/AmqpConsumerTest.php | 18 ++-- pkg/amqp-lib/Tests/AmqpContextTest.php | 89 +++++-------------- pkg/amqp-lib/Tests/AmqpProducerTest.php | 16 ++-- pkg/amqp-lib/Tests/BufferTest.php | 2 +- pkg/amqp-lib/Tests/Spec/AmqpMessageTest.php | 17 ---- pkg/amqp-lib/Tests/Spec/AmqpQueueTest.php | 14 --- .../AmqpSendToAndReceiveFromQueueTest.php | 2 +- .../AmqpSendToAndReceiveFromTopicTest.php | 5 +- ...mqpSendToAndReceiveNoWaitFromQueueTest.php | 2 +- ...mqpSendToAndReceiveNoWaitFromTopicTest.php | 5 +- ...iveFromQueueWithBasicConsumeMethodTest.php | 10 ++- ...ReceiveFromQueueWithBasicGetMethodTest.php | 10 ++- ...ndToTopicAndReceiveNoWaitFromQueueTest.php | 10 ++- pkg/amqp-lib/Tests/Spec/AmqpTopicTest.php | 14 --- 14 files changed, 66 insertions(+), 148 deletions(-) delete mode 100644 pkg/amqp-lib/Tests/Spec/AmqpMessageTest.php delete mode 100644 pkg/amqp-lib/Tests/Spec/AmqpQueueTest.php delete mode 100644 pkg/amqp-lib/Tests/Spec/AmqpTopicTest.php diff --git a/pkg/amqp-lib/Tests/AmqpConsumerTest.php b/pkg/amqp-lib/Tests/AmqpConsumerTest.php index a77443223..9b4ee51b9 100644 --- a/pkg/amqp-lib/Tests/AmqpConsumerTest.php +++ b/pkg/amqp-lib/Tests/AmqpConsumerTest.php @@ -3,12 +3,12 @@ namespace Enqueue\AmqpLib\Tests; use Enqueue\AmqpLib\AmqpConsumer; -use Enqueue\AmqpLib\AmqpMessage; -use Enqueue\AmqpLib\AmqpQueue; use Enqueue\AmqpLib\Buffer; use Enqueue\Null\NullMessage; use Enqueue\Test\ClassExtensionTrait; use Enqueue\Test\WriteAttributeTrait; +use Interop\Amqp\Impl\AmqpMessage; +use Interop\Amqp\Impl\AmqpQueue; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrConsumer; use PhpAmqpLib\Channel\AMQPChannel; @@ -48,7 +48,7 @@ public function testOnAcknowledgeShouldThrowExceptionIfNotAmqpMessage() $consumer = new AmqpConsumer($this->createChannelMock(), new AmqpQueue('aName'), new Buffer(), 'basic_get'); $this->expectException(InvalidMessageException::class); - $this->expectExceptionMessage('The message must be an instance of Enqueue\AmqpLib\AmqpMessage but'); + $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but'); $consumer->acknowledge(new NullMessage()); } @@ -58,7 +58,7 @@ public function testOnRejectShouldThrowExceptionIfNotAmqpMessage() $consumer = new AmqpConsumer($this->createChannelMock(), new AmqpQueue('aName'), new Buffer(), 'basic_get'); $this->expectException(InvalidMessageException::class); - $this->expectExceptionMessage('The message must be an instance of Enqueue\AmqpLib\AmqpMessage but'); + $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but'); $consumer->reject(new NullMessage()); } @@ -157,21 +157,19 @@ public function testShouldCallExpectedMethodsWhenReceiveWithBasicConsumeMethod() ->method('basic_consume') ->willReturn('consumer-tag') ; - $channel - ->expects($this->once()) - ->method('basic_qos') - ->with($this->identicalTo(0), $this->identicalTo(1), $this->isFalse()) - ; $channel ->expects($this->once()) ->method('wait') + ->willReturnCallback(function() { + usleep(2000); + }); ; $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_consume'); $message = new AmqpMessage(); $message->setDeliveryTag('delivery-tag'); - $consumer->receive(); + $consumer->receive(1); } /** diff --git a/pkg/amqp-lib/Tests/AmqpContextTest.php b/pkg/amqp-lib/Tests/AmqpContextTest.php index 17070f072..4ee2fe7fa 100644 --- a/pkg/amqp-lib/Tests/AmqpContextTest.php +++ b/pkg/amqp-lib/Tests/AmqpContextTest.php @@ -3,11 +3,10 @@ namespace Enqueue\AmqpLib\Tests; use Enqueue\AmqpLib\AmqpContext; -use Enqueue\AmqpLib\AmqpQueue; -use Enqueue\AmqpLib\AmqpTopic; use Enqueue\Null\NullQueue; -use Enqueue\Null\NullTopic; -use Interop\Queue\Exception; +use Interop\Amqp\Impl\AmqpBind; +use Interop\Amqp\Impl\AmqpQueue; +use Interop\Amqp\Impl\AmqpTopic; use Interop\Queue\InvalidDestinationException; use PhpAmqpLib\Channel\AMQPChannel; use PhpAmqpLib\Connection\AbstractConnection; @@ -30,7 +29,7 @@ public function testShouldDeclareTopic() $this->isTrue(), $this->isTrue(), $this->identicalTo(['key' => 'value']), - $this->identicalTo(12345) + $this->isNull() ) ; @@ -44,13 +43,11 @@ public function testShouldDeclareTopic() $topic = new AmqpTopic('name'); $topic->setType('type'); $topic->setArguments(['key' => 'value']); - $topic->setAutoDelete(true); - $topic->setDurable(true); - $topic->setInternal(true); - $topic->setNoWait(true); - $topic->setPassive(true); - $topic->setRoutingKey('routing-key'); - $topic->setTicket(12345); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); + $topic->addFlag(AmqpTopic::FLAG_NOWAIT); + $topic->addFlag(AmqpTopic::FLAG_PASSIVE); + $topic->addFlag(AmqpTopic::FLAG_INTERNAL); + $topic->addFlag(AmqpTopic::FLAG_AUTODELETE); $session = new AmqpContext($connection, ''); $session->declareTopic($topic); @@ -70,7 +67,7 @@ public function testShouldDeclareQueue() $this->isTrue(), $this->isTrue(), $this->identicalTo(['key' => 'value']), - $this->identicalTo(12345) + $this->isNull() ) ; @@ -83,49 +80,17 @@ public function testShouldDeclareQueue() $queue = new AmqpQueue('name'); $queue->setArguments(['key' => 'value']); - $queue->setAutoDelete(true); - $queue->setDurable(true); - $queue->setNoWait(true); - $queue->setPassive(true); - $queue->setTicket(12345); - $queue->setConsumerTag('consumer-tag'); - $queue->setExclusive(true); - $queue->setNoLocal(true); + $queue->addFlag(AmqpQueue::FLAG_AUTODELETE); + $queue->addFlag(AmqpQueue::FLAG_DURABLE); + $queue->addFlag(AmqpQueue::FLAG_NOWAIT); + $queue->addFlag(AmqpQueue::FLAG_PASSIVE); + $queue->addFlag(AmqpQueue::FLAG_EXCLUSIVE); + $queue->addFlag(AmqpQueue::FLAG_NOWAIT); $session = new AmqpContext($connection, ''); $session->declareQueue($queue); } - public function testDeclareBindShouldThrowExceptionIfSourceDestinationIsInvalid() - { - $context = new AmqpContext($this->createConnectionMock(), ''); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpLib\AmqpTopic but got'); - - $context->bind(new NullTopic(''), new AmqpTopic('name')); - } - - public function testDeclareBindShouldThrowExceptionIfTargetDestinationIsInvalid() - { - $context = new AmqpContext($this->createConnectionMock(), ''); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpLib\AmqpTopic but got'); - - $context->bind(new AmqpQueue('name'), new NullTopic('')); - } - - public function testDeclareBindShouldThrowExceptionWhenSourceAndTargetAreQueues() - { - $context = new AmqpContext($this->createConnectionMock(), ''); - - $this->expectException(Exception::class); - $this->expectExceptionMessage('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic'); - - $context->bind(new AmqpQueue('name'), new AmqpQueue('name')); - } - public function testDeclareBindShouldBindTopicToTopic() { $source = new AmqpTopic('source'); @@ -135,7 +100,7 @@ public function testDeclareBindShouldBindTopicToTopic() $channel ->expects($this->once()) ->method('exchange_bind') - ->with('target', 'source') + ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue()) ; $connection = $this->createConnectionMock(); @@ -146,7 +111,7 @@ public function testDeclareBindShouldBindTopicToTopic() ; $context = new AmqpContext($connection, ''); - $context->bind($source, $target); + $context->bind(new AmqpBind($target, $source, 'routing-key', 12345)); } public function testDeclareBindShouldBindTopicToQueue() @@ -158,7 +123,7 @@ public function testDeclareBindShouldBindTopicToQueue() $channel ->expects($this->exactly(2)) ->method('queue_bind') - ->with('target', 'source') + ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue()) ; $connection = $this->createConnectionMock(); @@ -169,8 +134,8 @@ public function testDeclareBindShouldBindTopicToQueue() ; $context = new AmqpContext($connection, ''); - $context->bind($source, $target); - $context->bind($target, $source); + $context->bind(new AmqpBind($target, $source, 'routing-key', 12345)); + $context->bind(new AmqpBind($source, $target, 'routing-key', 12345)); } public function testShouldCloseChannelConnection() @@ -194,16 +159,6 @@ public function testShouldCloseChannelConnection() $context->close(); } - public function testPurgeShouldThrowExceptionIfDestinationIsNotAmqpQueue() - { - $context = new AmqpContext($this->createConnectionMock(), ''); - - $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpLib\AmqpQueue but got'); - - $context->purge(new NullQueue('')); - } - public function testShouldPurgeQueue() { $queue = new AmqpQueue('queue'); @@ -223,7 +178,7 @@ public function testShouldPurgeQueue() ; $context = new AmqpContext($connection, ''); - $context->purge($queue); + $context->purgeQueue($queue); } /** diff --git a/pkg/amqp-lib/Tests/AmqpProducerTest.php b/pkg/amqp-lib/Tests/AmqpProducerTest.php index cfad057f4..1d389bf3c 100644 --- a/pkg/amqp-lib/Tests/AmqpProducerTest.php +++ b/pkg/amqp-lib/Tests/AmqpProducerTest.php @@ -2,11 +2,11 @@ namespace Enqueue\AmqpLib\Tests; -use Enqueue\AmqpLib\AmqpMessage; use Enqueue\AmqpLib\AmqpProducer; -use Enqueue\AmqpLib\AmqpQueue; -use Enqueue\AmqpLib\AmqpTopic; use Enqueue\Test\ClassExtensionTrait; +use Interop\Amqp\Impl\AmqpMessage; +use Interop\Amqp\Impl\AmqpQueue; +use Interop\Amqp\Impl\AmqpTopic; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -36,7 +36,7 @@ public function testShouldThrowExceptionWhenDestinationTypeIsInvalid() $producer = new AmqpProducer($this->createAmqpChannelMock()); $this->expectException(InvalidDestinationException::class); - $this->expectExceptionMessage('The destination must be an instance of Enqueue\AmqpLib\AmqpQueue but got'); + $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpQueue but got'); $producer->send($this->createDestinationMock(), new AmqpMessage()); } @@ -46,7 +46,7 @@ public function testShouldThrowExceptionWhenMessageTypeIsInvalid() $producer = new AmqpProducer($this->createAmqpChannelMock()); $this->expectException(InvalidMessageException::class); - $this->expectExceptionMessage('The message must be an instance of Enqueue\AmqpLib\AmqpMessage but it is'); + $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but it is'); $producer->send(new AmqpTopic('name'), $this->createMessageMock()); } @@ -66,10 +66,12 @@ public function testShouldPublishMessageToTopic() ; $topic = new AmqpTopic('topic'); - $topic->setRoutingKey('routing-key'); + + $message = new AmqpMessage('body'); + $message->setRoutingKey('routing-key'); $producer = new AmqpProducer($channel); - $producer->send($topic, new AmqpMessage('body')); + $producer->send($topic, $message); $this->assertEquals('body', $amqpMessage->getBody()); } diff --git a/pkg/amqp-lib/Tests/BufferTest.php b/pkg/amqp-lib/Tests/BufferTest.php index 981ff2b16..bebe435cb 100644 --- a/pkg/amqp-lib/Tests/BufferTest.php +++ b/pkg/amqp-lib/Tests/BufferTest.php @@ -2,8 +2,8 @@ namespace Enqueue\AmqpLib\Tests; -use Enqueue\AmqpLib\AmqpMessage; use Enqueue\AmqpLib\Buffer; +use Interop\Amqp\Impl\AmqpMessage; use PHPUnit\Framework\TestCase; class BufferTest extends TestCase diff --git a/pkg/amqp-lib/Tests/Spec/AmqpMessageTest.php b/pkg/amqp-lib/Tests/Spec/AmqpMessageTest.php deleted file mode 100644 index 57b93cbd0..000000000 --- a/pkg/amqp-lib/Tests/Spec/AmqpMessageTest.php +++ /dev/null @@ -1,17 +0,0 @@ -createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); return $queue; } diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php index dfce6ccdf..d1e78e900 100644 --- a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php @@ -4,6 +4,7 @@ use Enqueue\AmqpLib\AmqpConnectionFactory; use Enqueue\AmqpLib\AmqpContext; +use Interop\Amqp\AmqpTopic; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToAndReceiveFromTopicSpec; @@ -30,8 +31,8 @@ protected function createContext() protected function createTopic(PsrContext $context, $topicName) { $topic = $context->createTopic($topicName); - $topic->setType('fanout'); - $topic->setDurable(true); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php index b4db35c10..d36b168fc 100644 --- a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php @@ -31,7 +31,7 @@ protected function createQueue(PsrContext $context, $queueName) { $queue = $context->createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); return $queue; } diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php index a50fc4c67..d237895e0 100644 --- a/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php @@ -4,6 +4,7 @@ use Enqueue\AmqpLib\AmqpConnectionFactory; use Enqueue\AmqpLib\AmqpContext; +use Interop\Amqp\AmqpTopic; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToAndReceiveNoWaitFromTopicSpec; @@ -30,8 +31,8 @@ protected function createContext() protected function createTopic(PsrContext $context, $topicName) { $topic = $context->createTopic($topicName); - $topic->setType('fanout'); - $topic->setDurable(true); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php index 8af921998..5947a7cd1 100644 --- a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php @@ -4,6 +4,8 @@ use Enqueue\AmqpLib\AmqpConnectionFactory; use Enqueue\AmqpLib\AmqpContext; +use Interop\Amqp\AmqpTopic; +use Interop\Amqp\Impl\AmqpBind; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToTopicAndReceiveFromQueueSpec; @@ -33,9 +35,9 @@ protected function createQueue(PsrContext $context, $queueName) $queue = $context->createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); - $context->bind($context->createTopic($queueName), $queue); + $context->bind(new AmqpBind($context->createTopic($queueName), $queue)); return $queue; } @@ -50,8 +52,8 @@ protected function createTopic(PsrContext $context, $topicName) $topicName .= '_basic_consume'; $topic = $context->createTopic($topicName); - $topic->setType('fanout'); - $topic->setDurable(true); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php index 28192181f..c5512ef35 100644 --- a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php @@ -4,6 +4,8 @@ use Enqueue\AmqpLib\AmqpConnectionFactory; use Enqueue\AmqpLib\AmqpContext; +use Interop\Amqp\AmqpTopic; +use Interop\Amqp\Impl\AmqpBind; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToTopicAndReceiveFromQueueSpec; @@ -31,9 +33,9 @@ protected function createQueue(PsrContext $context, $queueName) { $queue = $context->createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); - $context->bind($context->createTopic($queueName), $queue); + $context->bind(new AmqpBind($context->createTopic($queueName), $queue)); return $queue; } @@ -46,8 +48,8 @@ protected function createQueue(PsrContext $context, $queueName) protected function createTopic(PsrContext $context, $topicName) { $topic = $context->createTopic($topicName); - $topic->setType('fanout'); - $topic->setDurable(true); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php index 6b4b1906b..783496ffa 100644 --- a/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php @@ -4,6 +4,8 @@ use Enqueue\AmqpLib\AmqpConnectionFactory; use Enqueue\AmqpLib\AmqpContext; +use Interop\Amqp\AmqpTopic; +use Interop\Amqp\Impl\AmqpBind; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendToTopicAndReceiveNoWaitFromQueueSpec; @@ -31,9 +33,9 @@ protected function createQueue(PsrContext $context, $queueName) { $queue = $context->createQueue($queueName); $context->declareQueue($queue); - $context->purge($queue); + $context->purgeQueue($queue); - $context->bind($context->createTopic($queueName), $queue); + $context->bind(new AmqpBind($context->createTopic($queueName), $queue)); return $queue; } @@ -46,8 +48,8 @@ protected function createQueue(PsrContext $context, $queueName) protected function createTopic(PsrContext $context, $topicName) { $topic = $context->createTopic($topicName); - $topic->setType('fanout'); - $topic->setDurable(true); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); $context->declareTopic($topic); return $topic; diff --git a/pkg/amqp-lib/Tests/Spec/AmqpTopicTest.php b/pkg/amqp-lib/Tests/Spec/AmqpTopicTest.php deleted file mode 100644 index 89717f01f..000000000 --- a/pkg/amqp-lib/Tests/Spec/AmqpTopicTest.php +++ /dev/null @@ -1,14 +0,0 @@ - Date: Thu, 27 Jul 2017 15:59:45 +0300 Subject: [PATCH 17/76] amqp lib interop --- pkg/amqp-lib/AmqpConsumer.php | 13 ++++---- pkg/amqp-lib/AmqpContext.php | 42 ++++++++++++------------- pkg/amqp-lib/AmqpProducer.php | 8 ++--- pkg/amqp-lib/Tests/AmqpConsumerTest.php | 3 +- pkg/amqp-lib/Tests/AmqpContextTest.php | 2 -- 5 files changed, 33 insertions(+), 35 deletions(-) diff --git a/pkg/amqp-lib/AmqpConsumer.php b/pkg/amqp-lib/AmqpConsumer.php index 055736f64..ce48a8fcb 100644 --- a/pkg/amqp-lib/AmqpConsumer.php +++ b/pkg/amqp-lib/AmqpConsumer.php @@ -147,7 +147,7 @@ public function receive($timeout = 0) */ public function receiveNoWait() { - if ($message = $this->channel->basic_get($this->queue->getQueueName(), !!($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK))) { + if ($message = $this->channel->basic_get($this->queue->getQueueName(), (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK))) { return $this->convertMessage($message); } } @@ -232,10 +232,10 @@ private function receiveBasicConsume($timeout) $consumerTag = $this->channel->basic_consume( $this->queue->getQueueName(), $this->getConsumerTag() ?: $this->getQueue()->getConsumerTag(), - !!($this->getFlags() & InteropAmqpConsumer::FLAG_NOLOCAL), - !!($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK), - !!($this->getFlags() & InteropAmqpConsumer::FLAG_EXCLUSIVE), - !!($this->getFlags() & InteropAmqpConsumer::FLAG_NOWAIT), + (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOLOCAL), + (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK), + (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_EXCLUSIVE), + (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOWAIT), $callback ); @@ -277,6 +277,7 @@ private function receiveBasicConsume($timeout) break; } } - } catch (AMQPTimeoutException $e) {} + } catch (AMQPTimeoutException $e) { + } } } diff --git a/pkg/amqp-lib/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php index b380264a8..2f74279db 100644 --- a/pkg/amqp-lib/AmqpContext.php +++ b/pkg/amqp-lib/AmqpContext.php @@ -3,10 +3,10 @@ namespace Enqueue\AmqpLib; use Interop\Amqp\AmqpBind as InteropAmqpBind; +use Interop\Amqp\AmqpContext as InteropAmqpContext; use Interop\Amqp\AmqpMessage as InteropAmqpMessage; use Interop\Amqp\AmqpQueue as InteropAmqpQueue; use Interop\Amqp\AmqpTopic as InteropAmqpTopic; -use Interop\Amqp\AmqpContext as InteropAmqpContext; use Interop\Amqp\Impl\AmqpBind; use Interop\Amqp\Impl\AmqpMessage; use Interop\Amqp\Impl\AmqpQueue; @@ -134,11 +134,11 @@ public function declareTopic(InteropAmqpTopic $topic) $this->getChannel()->exchange_declare( $topic->getTopicName(), $topic->getType(), - !!($topic->getFlags() & InteropAmqpTopic::FLAG_PASSIVE), - !!($topic->getFlags() & InteropAmqpTopic::FLAG_DURABLE), - !!($topic->getFlags() & InteropAmqpTopic::FLAG_AUTODELETE), - !!($topic->getFlags() & InteropAmqpTopic::FLAG_INTERNAL), - !!($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_PASSIVE), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_DURABLE), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_AUTODELETE), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_INTERNAL), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT), $topic->getArguments() ); } @@ -150,8 +150,8 @@ public function deleteTopic(InteropAmqpTopic $topic) { $this->getChannel()->exchange_delete( $topic->getTopicName(), - !!($topic->getFlags() & InteropAmqpTopic::FLAG_IFUNUSED), - !!($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT) + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_IFUNUSED), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT) ); } @@ -162,11 +162,11 @@ public function declareQueue(InteropAmqpQueue $queue) { return $this->getChannel()->queue_declare( $queue->getQueueName(), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_PASSIVE), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_DURABLE), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_EXCLUSIVE), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_AUTODELETE), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_PASSIVE), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_DURABLE), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_EXCLUSIVE), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_AUTODELETE), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT), $queue->getArguments() ); } @@ -178,9 +178,9 @@ public function deleteQueue(InteropAmqpQueue $queue) { $this->getChannel()->queue_delete( $queue->getQueueName(), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_IFUNUSED), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_IFEMPTY), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT) + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_IFUNUSED), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_IFEMPTY), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT) ); } @@ -191,7 +191,7 @@ public function purgeQueue(InteropAmqpQueue $queue) { $this->getChannel()->queue_purge( $queue->getQueueName(), - !!($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT) + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT) ); } @@ -210,7 +210,7 @@ public function bind(InteropAmqpBind $bind) $bind->getTarget()->getTopicName(), $bind->getSource()->getTopicName(), $bind->getRoutingKey(), - !!($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), $bind->getArguments() ); // bind queue to exchange @@ -219,7 +219,7 @@ public function bind(InteropAmqpBind $bind) $bind->getSource()->getQueueName(), $bind->getTarget()->getTopicName(), $bind->getRoutingKey(), - !!($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), $bind->getArguments() ); // bind exchange to queue @@ -228,7 +228,7 @@ public function bind(InteropAmqpBind $bind) $bind->getTarget()->getQueueName(), $bind->getSource()->getTopicName(), $bind->getRoutingKey(), - !!($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), $bind->getArguments() ); } @@ -249,7 +249,7 @@ public function unbind(InteropAmqpBind $bind) $bind->getTarget()->getTopicName(), $bind->getSource()->getTopicName(), $bind->getRoutingKey(), - !!($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), $bind->getArguments() ); // bind queue to exchange diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php index 8d83644e3..68c216960 100644 --- a/pkg/amqp-lib/AmqpProducer.php +++ b/pkg/amqp-lib/AmqpProducer.php @@ -56,16 +56,16 @@ public function send(PsrDestination $destination, PsrMessage $message) $amqpMessage, $destination->getTopicName(), $message->getRoutingKey(), - !!($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY), - !!($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE) + (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY), + (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE) ); } else { $this->channel->basic_publish( $amqpMessage, '', $destination->getQueueName(), - !!($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY), - !!($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE) + (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY), + (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE) ); } } diff --git a/pkg/amqp-lib/Tests/AmqpConsumerTest.php b/pkg/amqp-lib/Tests/AmqpConsumerTest.php index 9b4ee51b9..f4462e2ad 100644 --- a/pkg/amqp-lib/Tests/AmqpConsumerTest.php +++ b/pkg/amqp-lib/Tests/AmqpConsumerTest.php @@ -160,10 +160,9 @@ public function testShouldCallExpectedMethodsWhenReceiveWithBasicConsumeMethod() $channel ->expects($this->once()) ->method('wait') - ->willReturnCallback(function() { + ->willReturnCallback(function () { usleep(2000); }); - ; $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_consume'); diff --git a/pkg/amqp-lib/Tests/AmqpContextTest.php b/pkg/amqp-lib/Tests/AmqpContextTest.php index 4ee2fe7fa..a9eb297d4 100644 --- a/pkg/amqp-lib/Tests/AmqpContextTest.php +++ b/pkg/amqp-lib/Tests/AmqpContextTest.php @@ -3,11 +3,9 @@ namespace Enqueue\AmqpLib\Tests; use Enqueue\AmqpLib\AmqpContext; -use Enqueue\Null\NullQueue; use Interop\Amqp\Impl\AmqpBind; use Interop\Amqp\Impl\AmqpQueue; use Interop\Amqp\Impl\AmqpTopic; -use Interop\Queue\InvalidDestinationException; use PhpAmqpLib\Channel\AMQPChannel; use PhpAmqpLib\Connection\AbstractConnection; use PHPUnit\Framework\TestCase; From 6c30be44e9fe764029c7b3c268f08d3729c4e997 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Thu, 27 Jul 2017 16:25:59 +0300 Subject: [PATCH 18/76] amqp lib interop --- pkg/amqp-lib/Tests/AmqpContextTest.php | 115 ++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 3 deletions(-) diff --git a/pkg/amqp-lib/Tests/AmqpContextTest.php b/pkg/amqp-lib/Tests/AmqpContextTest.php index a9eb297d4..939dcfd39 100644 --- a/pkg/amqp-lib/Tests/AmqpContextTest.php +++ b/pkg/amqp-lib/Tests/AmqpContextTest.php @@ -51,6 +51,36 @@ public function testShouldDeclareTopic() $session->declareTopic($topic); } + public function testShouldDeleteTopic() + { + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('exchange_delete') + ->with( + $this->identicalTo('name'), + $this->isTrue(), + $this->isTrue() + ) + ; + + $connection = $this->createConnectionMock(); + $connection + ->expects($this->once()) + ->method('channel') + ->willReturn($channel) + ; + + $topic = new AmqpTopic('name'); + $topic->setType('type'); + $topic->setArguments(['key' => 'value']); + $topic->addFlag(AmqpTopic::FLAG_IFUNUSED); + $topic->addFlag(AmqpTopic::FLAG_NOWAIT); + + $session = new AmqpContext($connection, ''); + $session->deleteTopic($topic); + } + public function testShouldDeclareQueue() { $channel = $this->createChannelMock(); @@ -89,7 +119,38 @@ public function testShouldDeclareQueue() $session->declareQueue($queue); } - public function testDeclareBindShouldBindTopicToTopic() + public function testShouldDeleteQueue() + { + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('queue_delete') + ->with( + $this->identicalTo('name'), + $this->isTrue(), + $this->isTrue(), + $this->isTrue() + ) + ; + + $connection = $this->createConnectionMock(); + $connection + ->expects($this->once()) + ->method('channel') + ->willReturn($channel) + ; + + $queue = new AmqpQueue('name'); + $queue->setArguments(['key' => 'value']); + $queue->addFlag(AmqpQueue::FLAG_IFUNUSED); + $queue->addFlag(AmqpQueue::FLAG_IFEMPTY); + $queue->addFlag(AmqpQueue::FLAG_NOWAIT); + + $session = new AmqpContext($connection, ''); + $session->deleteQueue($queue); + } + + public function testBindShouldBindTopicToTopic() { $source = new AmqpTopic('source'); $target = new AmqpTopic('target'); @@ -112,7 +173,7 @@ public function testDeclareBindShouldBindTopicToTopic() $context->bind(new AmqpBind($target, $source, 'routing-key', 12345)); } - public function testDeclareBindShouldBindTopicToQueue() + public function testBindShouldBindTopicToQueue() { $source = new AmqpTopic('source'); $target = new AmqpQueue('target'); @@ -136,6 +197,53 @@ public function testDeclareBindShouldBindTopicToQueue() $context->bind(new AmqpBind($source, $target, 'routing-key', 12345)); } + public function testShouldUnBindTopicFromTopic() + { + $source = new AmqpTopic('source'); + $target = new AmqpTopic('target'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('exchange_unbind') + ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue()) + ; + + $connection = $this->createConnectionMock(); + $connection + ->expects($this->once()) + ->method('channel') + ->willReturn($channel) + ; + + $context = new AmqpContext($connection, ''); + $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345)); + } + + public function testShouldUnBindTopicFromQueue() + { + $source = new AmqpTopic('source'); + $target = new AmqpQueue('target'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->exactly(2)) + ->method('queue_unbind') + ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), ['key' => 'value']) + ; + + $connection = $this->createConnectionMock(); + $connection + ->expects($this->once()) + ->method('channel') + ->willReturn($channel) + ; + + $context = new AmqpContext($connection, ''); + $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345, ['key' => 'value'])); + $context->unbind(new AmqpBind($source, $target, 'routing-key', 12345, ['key' => 'value'])); + } + public function testShouldCloseChannelConnection() { $channel = $this->createChannelMock(); @@ -160,12 +268,13 @@ public function testShouldCloseChannelConnection() public function testShouldPurgeQueue() { $queue = new AmqpQueue('queue'); + $queue->addFlag(AmqpQueue::FLAG_NOWAIT); $channel = $this->createChannelMock(); $channel ->expects($this->once()) ->method('queue_purge') - ->with('queue') + ->with($this->identicalTo('queue'), $this->isTrue()) ; $connection = $this->createConnectionMock(); From 64f788d5491f005bcbf88ace46ffa796f9fa2ebd Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 27 Jul 2017 18:07:55 +0300 Subject: [PATCH 19/76] [composer] Add extensions to platform config. --- composer.json | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 49c274e6d..bbc95e5a0 100644 --- a/composer.json +++ b/composer.json @@ -51,7 +51,12 @@ } }, "config": { - "bin-dir": "bin" + "bin-dir": "bin", + "platform": { + "ext-amqp": "1.7", + "ext-gearman": "1.1", + "ext-rdkafka": "3.3" + } }, "repositories": [ { From e9a0c257555a1d61d65c3c3c58593731d103cbd7 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 27 Jul 2017 18:14:13 +0300 Subject: [PATCH 20/76] [travis] remove platforms req option. now it takes php ver into account --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 095fb584a..d80e9e708 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ install: - rm $HOME/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini; - echo "memory_limit=2048M" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - composer require symfony/symfony:${SYMFONY_VERSION} --no-update - - composer install --ignore-platform-reqs # ext-amqp is not installed + - composer install - if [ "$FUNCTIONAL_TESTS" = true ]; then docker --version; fi - if [ "$FUNCTIONAL_TESTS" = true ]; then docker-compose --version; fi - if [ "$FUNCTIONAL_TESTS" = true ]; then bin/dev -b; fi From dccd58b1333aed53632f1879f64afc6702b92bda Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 27 Jul 2017 18:19:29 +0300 Subject: [PATCH 21/76] require php stan only when it is needed. --- .travis.yml | 2 +- composer.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d80e9e708..d10e9a3fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,7 +46,7 @@ install: - if [ "$FUNCTIONAL_TESTS" = true ]; then bin/dev -b; fi script: - - if [ "$PHPSTAN" = true ]; then php -d memory_limit=512M bin/phpstan analyse -l 1 -c phpstan.neon pkg/amqp-ext pkg/async-event-dispatcher pkg/dbal pkg/enqueue pkg/enqueue-bundle pkg/fs pkg/gearman pkg/job-queue pkg/null pkg/pheanstalk pkg/redis pkg/simple-client pkg/sqs pkg/stomp pkg/test pkg/rdkafka; fi + - if [ "$PHPSTAN" = true ]; then composer require "phpstan/phpstan:0.7.0" ; php -d memory_limit=512M bin/phpstan analyse -l 1 -c phpstan.neon pkg/amqp-ext pkg/async-event-dispatcher pkg/dbal pkg/enqueue pkg/enqueue-bundle pkg/fs pkg/gearman pkg/job-queue pkg/null pkg/pheanstalk pkg/redis pkg/simple-client pkg/sqs pkg/stomp pkg/test pkg/rdkafka; fi - if [ "$PHP_CS_FIXER" = true ]; then IFS=$'\n'; COMMIT_SCA_FILES=($(git diff --name-only --diff-filter=ACMRTUXB "${TRAVIS_COMMIT_RANGE}")); unset IFS; fi - if [ "$PHP_CS_FIXER" = true ]; then ./bin/php-cs-fixer fix --config=.php_cs.dist -v --dry-run --stop-on-violation --using-cache=no --path-mode=intersection -- "${COMMIT_SCA_FILES[@]}"; fi - if [ "$UNIT_TESTS" = true ]; then bin/phpunit --exclude-group=functional; fi diff --git a/composer.json b/composer.json index bbc95e5a0..5b1aea2ef 100644 --- a/composer.json +++ b/composer.json @@ -35,8 +35,7 @@ "symfony/event-dispatcher": "^2.8|^3", "symfony/console": "^2.8|^3", "friendsofphp/php-cs-fixer": "^2", - "empi89/php-amqp-stubs": "*@dev", - "phpstan/phpstan": "^0.7.0" + "empi89/php-amqp-stubs": "*@dev" }, "autoload": { "files": [ From bb6a1828376584c4bebde0c7750ab7ef9b0523ec Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 27 Jul 2017 18:28:23 +0300 Subject: [PATCH 22/76] master is 0.7 --- pkg/amqp-ext/composer.json | 8 ++++---- pkg/amqp-lib/composer.json | 8 ++++---- pkg/async-event-dispatcher/composer.json | 4 ++-- pkg/dbal/composer.json | 8 ++++---- pkg/enqueue-bundle/composer.json | 24 ++++++++++++------------ pkg/enqueue/composer.json | 20 ++++++++++---------- pkg/fs/composer.json | 8 ++++---- pkg/gearman/composer.json | 8 ++++---- pkg/job-queue/composer.json | 8 ++++---- pkg/null/composer.json | 6 +++--- pkg/pheanstalk/composer.json | 8 ++++---- pkg/rdkafka/composer.json | 8 ++++---- pkg/redis/composer.json | 8 ++++---- pkg/simple-client/composer.json | 12 ++++++------ pkg/sqs/composer.json | 6 +++--- pkg/stomp/composer.json | 8 ++++---- pkg/test/composer.json | 2 +- 17 files changed, 77 insertions(+), 77 deletions(-) diff --git a/pkg/amqp-ext/composer.json b/pkg/amqp-ext/composer.json index 64ae37571..4f563ee13 100644 --- a/pkg/amqp-ext/composer.json +++ b/pkg/amqp-ext/composer.json @@ -18,9 +18,9 @@ }, "require-dev": { "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "empi89/php-amqp-stubs": "*@dev", "symfony/dependency-injection": "^2.8|^3", @@ -38,7 +38,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/amqp-lib/composer.json b/pkg/amqp-lib/composer.json index 16c83929f..3c1eaa09a 100644 --- a/pkg/amqp-lib/composer.json +++ b/pkg/amqp-lib/composer.json @@ -18,9 +18,9 @@ }, "require-dev": { "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -37,7 +37,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/async-event-dispatcher/composer.json b/pkg/async-event-dispatcher/composer.json index f6010afe7..122500207 100644 --- a/pkg/async-event-dispatcher/composer.json +++ b/pkg/async-event-dispatcher/composer.json @@ -21,7 +21,7 @@ "symfony/config": "^2.8|^3", "symfony/http-kernel": "^2.8|^3", "symfony/filesystem": "^2.8|^3", - "enqueue/null": "^0.6@dev" + "enqueue/null": "^0.7@dev" }, "suggest": { "symfony/dependency-injection": "^2.8|^3 If you'd like to use async event dispatcher container extension." @@ -35,7 +35,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/dbal/composer.json b/pkg/dbal/composer.json index 2d550d8ba..6d7241de5 100644 --- a/pkg/dbal/composer.json +++ b/pkg/dbal/composer.json @@ -18,9 +18,9 @@ }, "require-dev": { "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -37,7 +37,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/enqueue-bundle/composer.json b/pkg/enqueue-bundle/composer.json index 6a00b724e..d508e3ebe 100644 --- a/pkg/enqueue-bundle/composer.json +++ b/pkg/enqueue-bundle/composer.json @@ -13,20 +13,20 @@ "require": { "php": ">=5.6", "symfony/framework-bundle": "^2.8|^3", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", - "enqueue/async-event-dispatcher": "^0.6@dev" + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", + "enqueue/async-event-dispatcher": "^0.7@dev" }, "require-dev": { "phpunit/phpunit": "~5.5", - "enqueue/stomp": "^0.6@dev", - "enqueue/amqp-ext": "^0.6@dev", - "enqueue/job-queue": "^0.6@dev", - "enqueue/fs": "^0.6@dev", - "enqueue/redis": "^0.6@dev", - "enqueue/dbal": "^0.6@dev", - "enqueue/sqs": "^0.6@dev", - "enqueue/test": "^0.6@dev", + "enqueue/stomp": "^0.7@dev", + "enqueue/amqp-ext": "^0.7@dev", + "enqueue/job-queue": "^0.7@dev", + "enqueue/fs": "^0.7@dev", + "enqueue/redis": "^0.7@dev", + "enqueue/dbal": "^0.7@dev", + "enqueue/sqs": "^0.7@dev", + "enqueue/test": "^0.7@dev", "doctrine/doctrine-bundle": "~1.2", "symfony/monolog-bundle": "^2.8|^3", "symfony/browser-kit": "^2.8|^3", @@ -40,7 +40,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/enqueue/composer.json b/pkg/enqueue/composer.json index 92acc093c..057979af9 100644 --- a/pkg/enqueue/composer.json +++ b/pkg/enqueue/composer.json @@ -13,7 +13,7 @@ "require": { "php": ">=5.6", "queue-interop/queue-interop": "^0.5@dev", - "enqueue/null": "^0.6@dev", + "enqueue/null": "^0.7@dev", "ramsey/uuid": "^2|^3.5" }, "require-dev": { @@ -23,14 +23,14 @@ "symfony/config": "^2.8|^3", "symfony/event-dispatcher": "^2.8|^3", "symfony/http-kernel": "^2.8|^3", - "enqueue/amqp-ext": "^0.6@dev", - "enqueue/pheanstalk": "^0.6@dev", - "enqueue/gearman": "^0.6@dev", - "enqueue/rdkafka": "^0.6@dev", - "enqueue/dbal": "^0.6@dev", - "enqueue/fs": "^0.6@dev", - "enqueue/test": "^0.6@dev", - "enqueue/simple-client": "^0.6@dev", + "enqueue/amqp-ext": "^0.7@dev", + "enqueue/pheanstalk": "^0.7@dev", + "enqueue/gearman": "^0.7@dev", + "enqueue/rdkafka": "^0.7@dev", + "enqueue/dbal": "^0.7@dev", + "enqueue/fs": "^0.7@dev", + "enqueue/test": "^0.7@dev", + "enqueue/simple-client": "^0.7@dev", "empi89/php-amqp-stubs": "*@dev" }, "suggest": { @@ -54,7 +54,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/fs/composer.json b/pkg/fs/composer.json index 55317f73b..edaeb297b 100644 --- a/pkg/fs/composer.json +++ b/pkg/fs/composer.json @@ -19,9 +19,9 @@ }, "require-dev": { "phpunit/phpunit": "~5.5", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", - "enqueue/test": "^0.6@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", + "enqueue/test": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -35,7 +35,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/gearman/composer.json b/pkg/gearman/composer.json index e70fc7134..520a18cec 100644 --- a/pkg/gearman/composer.json +++ b/pkg/gearman/composer.json @@ -17,9 +17,9 @@ }, "require-dev": { "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -36,7 +36,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/job-queue/composer.json b/pkg/job-queue/composer.json index ae9e1b16d..918df1bdd 100644 --- a/pkg/job-queue/composer.json +++ b/pkg/job-queue/composer.json @@ -13,13 +13,13 @@ "require": { "php": ">=5.6", "symfony/framework-bundle": "^2.8|^3", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "doctrine/orm": "~2.4" }, "require-dev": { "phpunit/phpunit": "~5.5", - "enqueue/test": "^0.6@dev", + "enqueue/test": "^0.7@dev", "doctrine/doctrine-bundle": "~1.2", "symfony/browser-kit": "^2.8|^3", "symfony/expression-language": "^2.8|^3" @@ -33,7 +33,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/null/composer.json b/pkg/null/composer.json index 5cf4e612f..529deca4d 100644 --- a/pkg/null/composer.json +++ b/pkg/null/composer.json @@ -17,8 +17,8 @@ }, "require-dev": { "phpunit/phpunit": "~5.5", - "enqueue/enqueue": "^0.6@dev", - "enqueue/test": "^0.6@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/test": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -32,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/pheanstalk/composer.json b/pkg/pheanstalk/composer.json index 8812fe21f..25c4f2225 100644 --- a/pkg/pheanstalk/composer.json +++ b/pkg/pheanstalk/composer.json @@ -17,9 +17,9 @@ }, "require-dev": { "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -36,7 +36,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/rdkafka/composer.json b/pkg/rdkafka/composer.json index d4eaf6458..9986ce546 100644 --- a/pkg/rdkafka/composer.json +++ b/pkg/rdkafka/composer.json @@ -18,9 +18,9 @@ }, "require-dev": { "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "kwn/php-rdkafka-stubs": "^1.0.2" }, @@ -47,7 +47,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/redis/composer.json b/pkg/redis/composer.json index c66dac27a..4ee0bf1a9 100644 --- a/pkg/redis/composer.json +++ b/pkg/redis/composer.json @@ -18,9 +18,9 @@ "require-dev": { "phpunit/phpunit": "~5.4.0", "predis/predis": "^1.1", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -39,7 +39,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/simple-client/composer.json b/pkg/simple-client/composer.json index 22d24d414..ee7f87067 100644 --- a/pkg/simple-client/composer.json +++ b/pkg/simple-client/composer.json @@ -12,17 +12,17 @@ ], "require": { "php": ">=5.6", - "enqueue/enqueue": "^0.6@dev", + "enqueue/enqueue": "^0.7@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3", "symfony/console": "^2.8|^3" }, "require-dev": { "phpunit/phpunit": "~5.5", - "enqueue/test": "^0.6@dev", - "enqueue/amqp-ext": "^0.6@dev", - "enqueue/fs": "^0.6@dev", - "enqueue/null": "^0.6@dev" + "enqueue/test": "^0.7@dev", + "enqueue/amqp-ext": "^0.7@dev", + "enqueue/fs": "^0.7@dev", + "enqueue/null": "^0.7@dev" }, "autoload": { "psr-4": { "Enqueue\\SimpleClient\\": "" }, @@ -33,7 +33,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/sqs/composer.json b/pkg/sqs/composer.json index 14a820964..fd007abbc 100644 --- a/pkg/sqs/composer.json +++ b/pkg/sqs/composer.json @@ -18,8 +18,8 @@ }, "require-dev": { "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -36,7 +36,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/stomp/composer.json b/pkg/stomp/composer.json index 6600f4642..5fb04fea2 100644 --- a/pkg/stomp/composer.json +++ b/pkg/stomp/composer.json @@ -20,9 +20,9 @@ }, "require-dev": { "phpunit/phpunit": "~5.4.0", - "enqueue/test": "^0.6@dev", - "enqueue/enqueue": "^0.6@dev", - "enqueue/null": "^0.6@dev", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" @@ -39,7 +39,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } diff --git a/pkg/test/composer.json b/pkg/test/composer.json index 5b0c9d638..5c89bfd2e 100644 --- a/pkg/test/composer.json +++ b/pkg/test/composer.json @@ -7,7 +7,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "0.6.x-dev" + "dev-master": "0.7.x-dev" } } } From 6d8fed2369de11880c0b5de5b4ca32acc8cd0075 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Fri, 28 Jul 2017 11:16:50 +0300 Subject: [PATCH 23/76] amqp interop client --- pkg/amqp-ext/Symfony/AmqpTransportFactory.php | 2 +- .../Symfony/RabbitMqAmqpTransportFactory.php | 2 +- .../Symfony/AmqpTransportFactoryTest.php | 2 +- .../RabbitMqAmqpTransportFactoryTest.php | 2 +- .../Client/Amqp}/AmqpDriver.php | 4 +- .../Client/Amqp}/RabbitMqDriver.php | 4 +- .../Tests/Client/Amqp}/AmqpDriverTest.php | 46 +++++++------- .../Tests/Client/Amqp}/RabbitMqDriverTest.php | 63 +++++++++---------- 8 files changed, 62 insertions(+), 63 deletions(-) rename pkg/{amqp-ext/Client => enqueue/Client/Amqp}/AmqpDriver.php (98%) rename pkg/{amqp-ext/Client => enqueue/Client/Amqp}/RabbitMqDriver.php (98%) rename pkg/{amqp-ext/Tests/Client => enqueue/Tests/Client/Amqp}/AmqpDriverTest.php (91%) rename pkg/{amqp-ext/Tests/Client => enqueue/Tests/Client/Amqp}/RabbitMqDriverTest.php (92%) diff --git a/pkg/amqp-ext/Symfony/AmqpTransportFactory.php b/pkg/amqp-ext/Symfony/AmqpTransportFactory.php index f275c7f85..e2a80b826 100644 --- a/pkg/amqp-ext/Symfony/AmqpTransportFactory.php +++ b/pkg/amqp-ext/Symfony/AmqpTransportFactory.php @@ -4,7 +4,7 @@ use Enqueue\AmqpExt\AmqpConnectionFactory; use Enqueue\AmqpExt\AmqpContext; -use Enqueue\AmqpExt\Client\AmqpDriver; +use Enqueue\Client\Amqp\AmqpDriver; use Enqueue\Symfony\DriverFactoryInterface; use Enqueue\Symfony\TransportFactoryInterface; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; diff --git a/pkg/amqp-ext/Symfony/RabbitMqAmqpTransportFactory.php b/pkg/amqp-ext/Symfony/RabbitMqAmqpTransportFactory.php index 7c3539aa2..11ef70342 100644 --- a/pkg/amqp-ext/Symfony/RabbitMqAmqpTransportFactory.php +++ b/pkg/amqp-ext/Symfony/RabbitMqAmqpTransportFactory.php @@ -2,7 +2,7 @@ namespace Enqueue\AmqpExt\Symfony; -use Enqueue\AmqpExt\Client\RabbitMqDriver; +use Enqueue\Client\Amqp\RabbitMqDriver; use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; diff --git a/pkg/amqp-ext/Tests/Symfony/AmqpTransportFactoryTest.php b/pkg/amqp-ext/Tests/Symfony/AmqpTransportFactoryTest.php index eafeaa96d..115211b38 100644 --- a/pkg/amqp-ext/Tests/Symfony/AmqpTransportFactoryTest.php +++ b/pkg/amqp-ext/Tests/Symfony/AmqpTransportFactoryTest.php @@ -3,8 +3,8 @@ namespace Enqueue\AmqpExt\Tests\Symfony; use Enqueue\AmqpExt\AmqpConnectionFactory; -use Enqueue\AmqpExt\Client\AmqpDriver; use Enqueue\AmqpExt\Symfony\AmqpTransportFactory; +use Enqueue\Client\Amqp\AmqpDriver; use Enqueue\Symfony\TransportFactoryInterface; use Enqueue\Test\ClassExtensionTrait; use PHPUnit\Framework\TestCase; diff --git a/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php b/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php index a553f9b01..46f530042 100644 --- a/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php +++ b/pkg/amqp-ext/Tests/Symfony/RabbitMqAmqpTransportFactoryTest.php @@ -3,9 +3,9 @@ namespace Enqueue\AmqpExt\Tests\Symfony; use Enqueue\AmqpExt\AmqpConnectionFactory; -use Enqueue\AmqpExt\Client\RabbitMqDriver; use Enqueue\AmqpExt\Symfony\AmqpTransportFactory; use Enqueue\AmqpExt\Symfony\RabbitMqAmqpTransportFactory; +use Enqueue\Client\Amqp\RabbitMqDriver; use Enqueue\Symfony\TransportFactoryInterface; use Enqueue\Test\ClassExtensionTrait; use PHPUnit\Framework\TestCase; diff --git a/pkg/amqp-ext/Client/AmqpDriver.php b/pkg/enqueue/Client/Amqp/AmqpDriver.php similarity index 98% rename from pkg/amqp-ext/Client/AmqpDriver.php rename to pkg/enqueue/Client/Amqp/AmqpDriver.php index 0a636518d..e8b5871d3 100644 --- a/pkg/amqp-ext/Client/AmqpDriver.php +++ b/pkg/enqueue/Client/Amqp/AmqpDriver.php @@ -1,12 +1,12 @@ createPsrContextMock(), + $this->createAmqpContextMock(), $this->createDummyConfig(), $this->createDummyQueueMetaRegistry() ); @@ -38,7 +38,7 @@ public function testShouldReturnConfigObject() { $config = $this->createDummyConfig(); - $driver = new AmqpDriver($this->createPsrContextMock(), $config, $this->createDummyQueueMetaRegistry()); + $driver = new AmqpDriver($this->createAmqpContextMock(), $config, $this->createDummyQueueMetaRegistry()); $this->assertSame($config, $driver->getConfig()); } @@ -47,7 +47,7 @@ public function testShouldCreateAndReturnQueueInstance() { $expectedQueue = new AmqpQueue('aName'); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createQueue') @@ -69,7 +69,7 @@ public function testShouldCreateAndReturnQueueInstanceWithHardcodedTransportName { $expectedQueue = new AmqpQueue('aName'); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createQueue') @@ -98,7 +98,7 @@ public function testShouldConvertTransportMessageToClientMessage() $transportMessage->setCorrelationId('theCorrelationId'); $driver = new AmqpDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), $this->createDummyConfig(), $this->createDummyQueueMetaRegistry() ); @@ -133,7 +133,7 @@ public function testShouldThrowExceptionIfExpirationIsNotNumeric() $transportMessage->setHeader('expiration', 'is-not-numeric'); $driver = new AmqpDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), $this->createDummyConfig(), $this->createDummyQueueMetaRegistry() ); @@ -157,7 +157,7 @@ public function testShouldConvertClientMessageToTransportMessage() $clientMessage->setReplyTo('theReplyTo'); $clientMessage->setCorrelationId('theCorrelationId'); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createMessage') @@ -198,13 +198,13 @@ public function testShouldSendMessageToRouter() $topic = new AmqpTopic(''); $transportMessage = new AmqpMessage(); - $producer = $this->createPsrProducerMock(); + $producer = $this->createAmqpProducerMock(); $producer ->expects($this->once()) ->method('send') ->with($this->identicalTo($topic), $this->identicalTo($transportMessage)) ; - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createTopic') @@ -236,7 +236,7 @@ public function testShouldSendMessageToRouter() public function testShouldThrowExceptionIfTopicParameterIsNotSet() { $driver = new AmqpDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), $this->createDummyConfig(), $this->createDummyQueueMetaRegistry() ); @@ -252,13 +252,13 @@ public function testShouldSendMessageToProcessor() $queue = new AmqpQueue(''); $transportMessage = new AmqpMessage(); - $producer = $this->createPsrProducerMock(); + $producer = $this->createAmqpProducerMock(); $producer ->expects($this->once()) ->method('send') ->with($this->identicalTo($queue), $this->identicalTo($transportMessage)) ; - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createQueue') @@ -291,7 +291,7 @@ public function testShouldSendMessageToProcessor() public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet() { $driver = new AmqpDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), $this->createDummyConfig(), $this->createDummyQueueMetaRegistry() ); @@ -305,7 +305,7 @@ public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet() public function testShouldThrowExceptionIfProcessorQueueNameParameterIsNotSet() { $driver = new AmqpDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), $this->createDummyConfig(), $this->createDummyQueueMetaRegistry() ); @@ -326,7 +326,7 @@ public function testShouldSetupBroker() $processorQueue = new AmqpQueue(''); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); // setup router $context ->expects($this->at(0)) @@ -381,17 +381,17 @@ public function testShouldSetupBroker() /** * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext */ - private function createPsrContextMock() + private function createAmqpContextMock() { return $this->createMock(AmqpContext::class); } /** - * @return \PHPUnit_Framework_MockObject_MockObject|PsrProducer + * @return \PHPUnit_Framework_MockObject_MockObject|AmqpProducer */ - private function createPsrProducerMock() + private function createAmqpProducerMock() { - return $this->createMock(PsrProducer::class); + return $this->createMock(AmqpProducer::class); } /** diff --git a/pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php b/pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php similarity index 92% rename from pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php rename to pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php index ac3e0dba9..698fc5c3e 100644 --- a/pkg/amqp-ext/Tests/Client/RabbitMqDriverTest.php +++ b/pkg/enqueue/Tests/Client/Amqp/RabbitMqDriverTest.php @@ -1,10 +1,9 @@ createPsrContextMock(), + $this->createAmqpContextMock(), Config::create(), $this->createDummyQueueMetaRegistry() ); @@ -45,7 +45,7 @@ public function testShouldReturnConfigObject() { $config = Config::create(); - $driver = new RabbitMqDriver($this->createPsrContextMock(), $config, $this->createDummyQueueMetaRegistry()); + $driver = new RabbitMqDriver($this->createAmqpContextMock(), $config, $this->createDummyQueueMetaRegistry()); $this->assertSame($config, $driver->getConfig()); } @@ -54,7 +54,7 @@ public function testShouldCreateAndReturnQueueInstance() { $expectedQueue = new AmqpQueue('aName'); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createQueue') @@ -76,7 +76,7 @@ public function testShouldCreateAndReturnQueueInstanceWithHardcodedTransportName { $expectedQueue = new AmqpQueue('aName'); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createQueue') @@ -107,7 +107,7 @@ public function testShouldConvertTransportMessageToClientMessage() $transportMessage->setCorrelationId('theCorrelationId'); $driver = new RabbitMqDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), new Config('', '', '', '', '', '', ['delay_plugin_installed' => true]), $this->createDummyQueueMetaRegistry() ); @@ -146,7 +146,7 @@ public function testShouldThrowExceptionIfXDelayIsNotNumeric() $transportMessage->setProperty('x-delay', 'is-not-numeric'); $driver = new RabbitMqDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), Config::create(), $this->createDummyQueueMetaRegistry() ); @@ -163,7 +163,7 @@ public function testShouldThrowExceptionIfExpirationIsNotNumeric() $transportMessage->setHeader('expiration', 'is-not-numeric'); $driver = new RabbitMqDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), Config::create(), $this->createDummyQueueMetaRegistry() ); @@ -180,7 +180,7 @@ public function testShouldThrowExceptionIfCantConvertTransportPriorityToClientPr $transportMessage->setHeader('priority', 'unknown'); $driver = new RabbitMqDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), Config::create(), $this->createDummyQueueMetaRegistry() ); @@ -196,7 +196,7 @@ public function testShouldThrowExceptionIfCantConvertClientPriorityToTransportPr $clientMessage = new Message(); $clientMessage->setPriority('unknown'); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createMessage') @@ -230,7 +230,7 @@ public function testShouldConvertClientMessageToTransportMessage() $clientMessage->setReplyTo('theReplyTo'); $clientMessage->setCorrelationId('theCorrelationId'); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createMessage') @@ -273,7 +273,7 @@ public function testThrowIfDelayNotSupportedOnConvertClientMessageToTransportMes $clientMessage = new Message(); $clientMessage->setDelay(432); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createMessage') @@ -296,13 +296,13 @@ public function testShouldSendMessageToRouter() $topic = new AmqpTopic(''); $transportMessage = new AmqpMessage(); - $producer = $this->createPsrProducerMock(); + $producer = $this->createAmqpProducerMock(); $producer ->expects($this->once()) ->method('send') ->with($this->identicalTo($topic), $this->identicalTo($transportMessage)) ; - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createTopic') @@ -334,7 +334,7 @@ public function testShouldSendMessageToRouter() public function testShouldThrowExceptionIfTopicParameterIsNotSet() { $driver = new RabbitMqDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), Config::create(), $this->createDummyQueueMetaRegistry() ); @@ -350,13 +350,13 @@ public function testShouldSendMessageToProcessor() $queue = new AmqpQueue(''); $transportMessage = new AmqpMessage(); - $producer = $this->createPsrProducerMock(); + $producer = $this->createAmqpProducerMock(); $producer ->expects($this->once()) ->method('send') ->with($this->identicalTo($queue), $this->identicalTo($transportMessage)) ; - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createQueue') @@ -392,13 +392,13 @@ public function testShouldSendMessageToDelayExchangeIfDelaySet() $delayTopic = new AmqpTopic(''); $transportMessage = new AmqpMessage(); - $producer = $this->createPsrProducerMock(); + $producer = $this->createAmqpProducerMock(); $producer ->expects($this->once()) ->method('send') ->with($this->identicalTo($delayTopic), $this->identicalTo($transportMessage)) ; - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); $context ->expects($this->once()) ->method('createQueue') @@ -437,7 +437,7 @@ public function testShouldSendMessageToDelayExchangeIfDelaySet() public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet() { $driver = new RabbitMqDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), Config::create(), $this->createDummyQueueMetaRegistry() ); @@ -451,7 +451,7 @@ public function testShouldThrowExceptionIfProcessorNameParameterIsNotSet() public function testShouldThrowExceptionIfProcessorQueueNameParameterIsNotSet() { $driver = new RabbitMqDriver( - $this->createPsrContextMock(), + $this->createAmqpContextMock(), Config::create(), $this->createDummyQueueMetaRegistry() ); @@ -471,9 +471,8 @@ public function testShouldSetupBrokerWhenDelayPluginNotInstalled() $routerQueue = new AmqpQueue(''); $processorQueue = new AmqpQueue(''); - $delayTopic = new AmqpTopic(''); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); // setup router $context ->expects($this->at(0)) @@ -524,7 +523,7 @@ public function testShouldSetupBroker() $processorQueue = new AmqpQueue(''); $delayTopic = new AmqpTopic(''); - $context = $this->createPsrContextMock(); + $context = $this->createAmqpContextMock(); // setup router $context ->expects($this->at(0)) @@ -596,17 +595,17 @@ public function testShouldSetupBroker() /** * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext */ - private function createPsrContextMock() + private function createAmqpContextMock() { return $this->createMock(AmqpContext::class); } /** - * @return \PHPUnit_Framework_MockObject_MockObject|PsrProducer + * @return \PHPUnit_Framework_MockObject_MockObject|AmqpProducer */ - private function createPsrProducerMock() + private function createAmqpProducerMock() { - return $this->createMock(PsrProducer::class); + return $this->createMock(AmqpProducer::class); } /** From 0240672439ef88f4553881932f1df439c2b3ae80 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Fri, 28 Jul 2017 11:18:09 +0300 Subject: [PATCH 24/76] fix typo --- pkg/sqs/Client/SqsDriver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/sqs/Client/SqsDriver.php b/pkg/sqs/Client/SqsDriver.php index dc14bf2ff..c86237309 100644 --- a/pkg/sqs/Client/SqsDriver.php +++ b/pkg/sqs/Client/SqsDriver.php @@ -97,7 +97,7 @@ public function setupBroker(LoggerInterface $logger = null) { $logger = $logger ?: new NullLogger(); $log = function ($text, ...$args) use ($logger) { - $logger->debug(sprintf('[AmqpDriver] '.$text, ...$args)); + $logger->debug(sprintf('[SqsDriver] '.$text, ...$args)); }; // setup router From 0b751a828b57c18635959d6cd6a88bb962354768 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Fri, 28 Jul 2017 14:10:18 +0300 Subject: [PATCH 25/76] amqp lib transport factory --- .../Symfony/AmqpLibTransportFactory.php | 168 ++++++++++++ .../RabbitMqAmqpLibTransportFactory.php | 53 ++++ .../Symfony/AmqpLibTransportFactoryTest.php | 239 ++++++++++++++++++ .../RabbitMqAmqpLibTransportFactoryTest.php | 144 +++++++++++ pkg/enqueue-bundle/EnqueueBundle.php | 8 + .../Tests/Unit/EnqueueBundleTest.php | 32 ++- 6 files changed, 640 insertions(+), 4 deletions(-) create mode 100644 pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php create mode 100644 pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php create mode 100644 pkg/amqp-lib/Tests/Symfony/AmqpLibTransportFactoryTest.php create mode 100644 pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php diff --git a/pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php b/pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php new file mode 100644 index 000000000..f2fbacdf5 --- /dev/null +++ b/pkg/amqp-lib/Symfony/AmqpLibTransportFactory.php @@ -0,0 +1,168 @@ +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('connection_timeout') + ->defaultValue(3.0) + ->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) + ->min(0) + ->info('Timeout in for income activity. Note: 0 or greater seconds. May be fractional.') + ->end() + ->integerNode('write_timeout') + ->defaultValue(3) + ->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() + ->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-lib/Symfony/RabbitMqAmqpLibTransportFactory.php b/pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php new file mode 100644 index 000000000..20765c6b1 --- /dev/null +++ b/pkg/amqp-lib/Symfony/RabbitMqAmqpLibTransportFactory.php @@ -0,0 +1,53 @@ +children() + ->booleanNode('delay_plugin_installed') + ->defaultFalse() + ->info('The option tells whether RabbitMQ broker has delay plugin installed or not') + ->end() + ; + } + + /** + * {@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 new file mode 100644 index 000000000..3aaf3bc6d --- /dev/null +++ b/pkg/amqp-lib/Tests/Symfony/AmqpLibTransportFactoryTest.php @@ -0,0 +1,239 @@ +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 new file mode 100644 index 000000000..22b1b4354 --- /dev/null +++ b/pkg/amqp-lib/Tests/Symfony/RabbitMqAmqpLibTransportFactoryTest.php @@ -0,0 +1,144 @@ +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_plugin_installed' => false, + '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_plugin_installed' => false, + ]); + + $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_plugin_installed' => false, + ]], $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_plugin_installed' => false, + ]); + + $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/enqueue-bundle/EnqueueBundle.php b/pkg/enqueue-bundle/EnqueueBundle.php index 3ce3480d1..c2c9b6bbc 100644 --- a/pkg/enqueue-bundle/EnqueueBundle.php +++ b/pkg/enqueue-bundle/EnqueueBundle.php @@ -5,6 +5,9 @@ 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\AsyncEventDispatcher\DependencyInjection\AsyncEventsPass; use Enqueue\AsyncEventDispatcher\DependencyInjection\AsyncTransformersPass; use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientExtensionsPass; @@ -58,6 +61,11 @@ public function build(ContainerBuilder $container) $extension->addTransportFactory(new RabbitMqAmqpTransportFactory()); } + if (class_exists(AmqpLibContext::class)) { + $extension->addTransportFactory(new AmqpLibTransportFactory()); + $extension->addTransportFactory(new RabbitMqAmqpLibTransportFactory()); + } + if (class_exists(FsContext::class)) { $extension->addTransportFactory(new FsTransportFactory()); } diff --git a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php index b9b369b5c..c989289ad 100644 --- a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php +++ b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php @@ -4,6 +4,8 @@ use Enqueue\AmqpExt\Symfony\AmqpTransportFactory; use Enqueue\AmqpExt\Symfony\RabbitMqAmqpTransportFactory; +use Enqueue\AmqpLib\Symfony\AmqpLibTransportFactory; +use Enqueue\AmqpLib\Symfony\RabbitMqAmqpLibTransportFactory; use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientExtensionsPass; use Enqueue\Bundle\DependencyInjection\Compiler\BuildClientRoutingPass; use Enqueue\Bundle\DependencyInjection\Compiler\BuildConsumptionExtensionsPass; @@ -132,7 +134,7 @@ public function testShouldRegisterAmqpAndRabbitMqAmqpTransportFactories() $bundle->build($container); } - public function testShouldRegisterFSTransportFactory() + public function testShouldRegisterAmqpLibAndRabbitMqAmqpLibTransportFactories() { $extensionMock = $this->createEnqueueExtensionMock(); @@ -142,6 +144,28 @@ public function testShouldRegisterFSTransportFactory() $extensionMock ->expects($this->at(4)) ->method('addTransportFactory') + ->with($this->isInstanceOf(AmqpLibTransportFactory::class)) + ; + $extensionMock + ->expects($this->at(5)) + ->method('addTransportFactory') + ->with($this->isInstanceOf(RabbitMqAmqpLibTransportFactory::class)) + ; + + $bundle = new EnqueueBundle(); + $bundle->build($container); + } + + public function testShouldRegisterFSTransportFactory() + { + $extensionMock = $this->createEnqueueExtensionMock(); + + $container = new ContainerBuilder(); + $container->registerExtension($extensionMock); + + $extensionMock + ->expects($this->at(6)) + ->method('addTransportFactory') ->with($this->isInstanceOf(FsTransportFactory::class)) ; @@ -157,7 +181,7 @@ public function testShouldRegisterRedisTransportFactory() $container->registerExtension($extensionMock); $extensionMock - ->expects($this->at(5)) + ->expects($this->at(7)) ->method('addTransportFactory') ->with($this->isInstanceOf(RedisTransportFactory::class)) ; @@ -174,7 +198,7 @@ public function testShouldRegisterDbalTransportFactory() $container->registerExtension($extensionMock); $extensionMock - ->expects($this->at(6)) + ->expects($this->at(8)) ->method('addTransportFactory') ->with($this->isInstanceOf(DbalTransportFactory::class)) ; @@ -191,7 +215,7 @@ public function testShouldRegisterSqsTransportFactory() $container->registerExtension($extensionMock); $extensionMock - ->expects($this->at(7)) + ->expects($this->at(9)) ->method('addTransportFactory') ->with($this->isInstanceOf(SqsTransportFactory::class)) ; From 528203bf03db9adff27a0784fdac8d819c70b689 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Fri, 28 Jul 2017 14:11:38 +0300 Subject: [PATCH 26/76] do not allow change consumer tag after consumer init --- pkg/amqp-ext/AmqpConsumer.php | 5 +++++ pkg/amqp-lib/AmqpConsumer.php | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/pkg/amqp-ext/AmqpConsumer.php b/pkg/amqp-ext/AmqpConsumer.php index 68d7a3dc9..1c84a4382 100644 --- a/pkg/amqp-ext/AmqpConsumer.php +++ b/pkg/amqp-ext/AmqpConsumer.php @@ -6,6 +6,7 @@ use Interop\Amqp\AmqpMessage as InteropAmqpMessage; use Interop\Amqp\AmqpQueue; use Interop\Amqp\Impl\AmqpMessage; +use Interop\Queue\Exception; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrMessage; @@ -73,6 +74,10 @@ public function __construct(AmqpContext $context, AmqpQueue $queue, Buffer $buff */ public function setConsumerTag($consumerTag) { + if ($this->isInit) { + throw new Exception('Consumer tag is not mutable after it has been subscribed to broker'); + } + $this->consumerTag = $consumerTag; } diff --git a/pkg/amqp-lib/AmqpConsumer.php b/pkg/amqp-lib/AmqpConsumer.php index ce48a8fcb..90f55f32d 100644 --- a/pkg/amqp-lib/AmqpConsumer.php +++ b/pkg/amqp-lib/AmqpConsumer.php @@ -73,6 +73,10 @@ public function __construct(AMQPChannel $channel, InteropAmqpQueue $queue, Buffe */ public function setConsumerTag($consumerTag) { + if ($this->isInit) { + throw new Exception('Consumer tag is not mutable after it has been subscribed to broker'); + } + $this->consumerTag = $consumerTag; } From 94fbe61f09cd5d005d2ef3c38725a5453aa0a533 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 31 Jul 2017 12:35:55 +0300 Subject: [PATCH 27/76] [composer] remove amqp interop from repositories --- composer.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/composer.json b/composer.json index 13d94c8d3..3d5146194 100644 --- a/composer.json +++ b/composer.json @@ -126,10 +126,6 @@ { "type": "path", "url": "pkg/async-event-dispatcher" - }, - { - "type": "vcs", - "url": "git@github.com:queue-interop/amqp-interop.git" } ] } From 8d57bb9760db1b309260605a6e8121dc2e5f3fc4 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 31 Jul 2017 13:52:04 +0300 Subject: [PATCH 28/76] [doc] fix doc --- docs/transport/amqp.md | 28 +++++++++++++++++----------- docs/transport/amqp_lib.md | 28 +++++++++++++++++----------- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/docs/transport/amqp.md b/docs/transport/amqp.md index 0862cee10..f28e45806 100644 --- a/docs/transport/amqp.md +++ b/docs/transport/amqp.md @@ -1,6 +1,6 @@ # AMQP transport -Implements [AMQP specifications](https://www.rabbitmq.com/specification.html). +Implements [AMQP specifications](https://www.rabbitmq.com/specification.html) and implements [amqp interop](https://github.com/queue-interop/amqp-interop) interfaces. Build on top of [php amqp extension](https://github.com/pdezwart/php-amqp). * [Installation](#installation) @@ -56,10 +56,12 @@ Declare topic operation creates a topic on a broker side. ```php createTopic('foo'); -$fooTopic->addFlag(AMQP_EX_TYPE_FANOUT); +$fooTopic->addFlag(AmqpTopic::TYPE_FANOUT); $psrContext->declareTopic($fooTopic); // to remove topic use delete topic method @@ -72,10 +74,12 @@ Declare queue operation creates a queue on a broker side. ```php createQueue('foo'); -$fooQueue->addFlag(AMQP_DURABLE); +$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE); $psrContext->declareQueue($fooQueue); // to remove topic use delete queue method @@ -88,11 +92,13 @@ Connects a queue to the topic. So messages from that topic comes to the queue an ```php bind($fooTopic, $fooQueue); +$psrContext->bind(new AmqpBind($fooTopic, $fooQueue)); ``` ## Send message to topic @@ -100,7 +106,7 @@ $psrContext->bind($fooTopic, $fooQueue); ```php createMessage('Hello world!'); @@ -112,7 +118,7 @@ $psrContext->createProducer()->send($fooTopic, $message); ```php createMessage('Hello world!'); @@ -124,7 +130,7 @@ $psrContext->createProducer()->send($fooQueue, $message); ```php createConsumer($fooQueue); @@ -141,11 +147,11 @@ $consumer->acknowledge($message); ```php createQueue('aQueue'); -$psrContext->purge($queue); +$psrContext->purgeQueue($queue); ``` [back to index](../index.md) \ No newline at end of file diff --git a/docs/transport/amqp_lib.md b/docs/transport/amqp_lib.md index 5e972f3f1..1cbf41abc 100644 --- a/docs/transport/amqp_lib.md +++ b/docs/transport/amqp_lib.md @@ -1,6 +1,6 @@ # AMQP transport -Implements [AMQP specifications](https://www.rabbitmq.com/specification.html). +Implements [AMQP specifications](https://www.rabbitmq.com/specification.html) and implements [amqp interop](https://github.com/queue-interop/amqp-interop) interfaces. Build on top of [php amqp lib](https://github.com/php-amqplib/php-amqplib). * [Installation](#installation) @@ -56,10 +56,12 @@ Declare topic operation creates a topic on a broker side. ```php createTopic('foo'); -$fooTopic->setType('fanout'); +$fooTopic->setType(AmqpTopic::TYPE_FANOUT); $psrContext->declareTopic($fooTopic); // to remove topic use delete topic method @@ -72,10 +74,12 @@ Declare queue operation creates a queue on a broker side. ```php createQueue('foo'); -$fooQueue->setDurable(true); +$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE); $psrContext->declareQueue($fooQueue); // to remove topic use delete queue method @@ -88,11 +92,13 @@ Connects a queue to the topic. So messages from that topic comes to the queue an ```php bind($fooTopic, $fooQueue); +$psrContext->bind(new AmqpBind($fooTopic, $fooQueue)); ``` ## Send message to topic @@ -100,7 +106,7 @@ $psrContext->bind($fooTopic, $fooQueue); ```php createMessage('Hello world!'); @@ -112,7 +118,7 @@ $psrContext->createProducer()->send($fooTopic, $message); ```php createMessage('Hello world!'); @@ -124,7 +130,7 @@ $psrContext->createProducer()->send($fooQueue, $message); ```php createConsumer($fooQueue); @@ -141,11 +147,11 @@ $consumer->acknowledge($message); ```php createQueue('aQueue'); -$psrContext->purge($queue); +$psrContext->purgeQueue($queue); ``` [back to index](../index.md) \ No newline at end of file From 48be799ab9fe49ae0918d5e1353a1f36f363dffe Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 31 Jul 2017 14:19:07 +0300 Subject: [PATCH 29/76] fix enqueue bundle tests run standalone. --- pkg/enqueue-bundle/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/enqueue-bundle/composer.json b/pkg/enqueue-bundle/composer.json index d508e3ebe..c43285e47 100644 --- a/pkg/enqueue-bundle/composer.json +++ b/pkg/enqueue-bundle/composer.json @@ -21,6 +21,7 @@ "phpunit/phpunit": "~5.5", "enqueue/stomp": "^0.7@dev", "enqueue/amqp-ext": "^0.7@dev", + "enqueue/amqp-lib": "^0.7@dev", "enqueue/job-queue": "^0.7@dev", "enqueue/fs": "^0.7@dev", "enqueue/redis": "^0.7@dev", From 48fecdb6491e6bb6411c4e9bae64191cc1e88290 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 31 Jul 2017 14:31:35 +0300 Subject: [PATCH 30/76] fix rdkafka tests run standalone --- pkg/rdkafka/.travis.yml | 3 ++- pkg/rdkafka/Tests/fix_composer_json.php | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 pkg/rdkafka/Tests/fix_composer_json.php diff --git a/pkg/rdkafka/.travis.yml b/pkg/rdkafka/.travis.yml index aaa1849c3..2f48cf85d 100644 --- a/pkg/rdkafka/.travis.yml +++ b/pkg/rdkafka/.travis.yml @@ -14,8 +14,9 @@ cache: - $HOME/.composer/cache install: + - php Tests/fix_composer_json.php - composer self-update - - composer install --prefer-source --ignore-platform-reqs + - composer install script: - vendor/bin/phpunit --exclude-group=functional diff --git a/pkg/rdkafka/Tests/fix_composer_json.php b/pkg/rdkafka/Tests/fix_composer_json.php new file mode 100644 index 000000000..03e9fd8a5 --- /dev/null +++ b/pkg/rdkafka/Tests/fix_composer_json.php @@ -0,0 +1,9 @@ + Date: Mon, 31 Jul 2017 14:33:17 +0300 Subject: [PATCH 31/76] fix amqp tests. --- pkg/amqp-ext/Tests/fix_composer_json.php | 9 +++++++++ pkg/rdkafka/Tests/fix_composer_json.php | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 pkg/amqp-ext/Tests/fix_composer_json.php diff --git a/pkg/amqp-ext/Tests/fix_composer_json.php b/pkg/amqp-ext/Tests/fix_composer_json.php new file mode 100644 index 000000000..fc430e276 --- /dev/null +++ b/pkg/amqp-ext/Tests/fix_composer_json.php @@ -0,0 +1,9 @@ + Date: Mon, 31 Jul 2017 14:45:03 +0300 Subject: [PATCH 32/76] fix tests. --- pkg/amqp-ext/.travis.yml | 3 ++- pkg/enqueue/.travis.yml | 3 ++- pkg/enqueue/Tests/fix_composer_json.php | 11 +++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 pkg/enqueue/Tests/fix_composer_json.php diff --git a/pkg/amqp-ext/.travis.yml b/pkg/amqp-ext/.travis.yml index ad53bf6b4..2f48cf85d 100644 --- a/pkg/amqp-ext/.travis.yml +++ b/pkg/amqp-ext/.travis.yml @@ -14,8 +14,9 @@ cache: - $HOME/.composer/cache install: + - php Tests/fix_composer_json.php - composer self-update - - composer install --prefer-source --ignore-platform-reqs # ext-amqp is not installed + - composer install script: - vendor/bin/phpunit --exclude-group=functional diff --git a/pkg/enqueue/.travis.yml b/pkg/enqueue/.travis.yml index aaa1849c3..2f48cf85d 100644 --- a/pkg/enqueue/.travis.yml +++ b/pkg/enqueue/.travis.yml @@ -14,8 +14,9 @@ cache: - $HOME/.composer/cache install: + - php Tests/fix_composer_json.php - composer self-update - - composer install --prefer-source --ignore-platform-reqs + - composer install script: - vendor/bin/phpunit --exclude-group=functional diff --git a/pkg/enqueue/Tests/fix_composer_json.php b/pkg/enqueue/Tests/fix_composer_json.php new file mode 100644 index 000000000..bce1ebb75 --- /dev/null +++ b/pkg/enqueue/Tests/fix_composer_json.php @@ -0,0 +1,11 @@ + Date: Mon, 31 Jul 2017 14:53:35 +0300 Subject: [PATCH 33/76] fix bundle tests. --- pkg/enqueue-bundle/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/enqueue-bundle/composer.json b/pkg/enqueue-bundle/composer.json index c43285e47..f70ab6af8 100644 --- a/pkg/enqueue-bundle/composer.json +++ b/pkg/enqueue-bundle/composer.json @@ -21,6 +21,7 @@ "phpunit/phpunit": "~5.5", "enqueue/stomp": "^0.7@dev", "enqueue/amqp-ext": "^0.7@dev", + "php-amqplib/php-amqplib": "^2.7@dev", "enqueue/amqp-lib": "^0.7@dev", "enqueue/job-queue": "^0.7@dev", "enqueue/fs": "^0.7@dev", From 1199813abfc2ac71fbb216c82a77a92d0c363c83 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Wed, 2 Aug 2017 11:09:32 +0300 Subject: [PATCH 34/76] implement qos --- pkg/amqp-ext/AmqpContext.php | 8 ++++ pkg/amqp-lib/AmqpConnectionFactory.php | 8 +++- pkg/amqp-lib/AmqpContext.php | 32 ++++++++++--- .../Tests/AmqpConnectionFactoryConfigTest.php | 27 +++++++++++ pkg/amqp-lib/Tests/AmqpContextTest.php | 45 ++++++++++++++----- pkg/amqp-lib/Tests/Spec/AmqpContextTest.php | 2 +- 6 files changed, 103 insertions(+), 19 deletions(-) diff --git a/pkg/amqp-ext/AmqpContext.php b/pkg/amqp-ext/AmqpContext.php index 6d1f40f06..32a135b18 100644 --- a/pkg/amqp-ext/AmqpContext.php +++ b/pkg/amqp-ext/AmqpContext.php @@ -255,6 +255,14 @@ public function close() } } + /** + * {@inheritdoc} + */ + public function setQos($prefetchSize, $prefetchCount, $global) + { + $this->getExtChannel()->qos($prefetchSize, $prefetchCount); + } + /** * @return \AMQPChannel */ diff --git a/pkg/amqp-lib/AmqpConnectionFactory.php b/pkg/amqp-lib/AmqpConnectionFactory.php index 9c1f02186..cbee87991 100644 --- a/pkg/amqp-lib/AmqpConnectionFactory.php +++ b/pkg/amqp-lib/AmqpConnectionFactory.php @@ -33,6 +33,9 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory * '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.', * ] * * or @@ -69,7 +72,7 @@ public function __construct($config = 'amqp://') */ public function createContext() { - return new AmqpContext($this->establishConnection(), $this->config['receive_method']); + return new AmqpContext($this->establishConnection(), $this->config); } /** @@ -224,6 +227,9 @@ private function defaultConfig() '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/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php index 2f74279db..e3f64776e 100644 --- a/pkg/amqp-lib/AmqpContext.php +++ b/pkg/amqp-lib/AmqpContext.php @@ -33,7 +33,7 @@ class AmqpContext implements InteropAmqpContext /** * @var string */ - private $receiveMethod; + private $config; /** * @var Buffer @@ -42,12 +42,18 @@ class AmqpContext implements InteropAmqpContext /** * @param AbstractConnection $connection - * @param string $receiveMethod + * @param array $config */ - public function __construct(AbstractConnection $connection, $receiveMethod) + public function __construct(AbstractConnection $connection, $config = []) { + $this->config = array_replace([ + 'receive_method' => 'basic_get', + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + ], $config); + $this->connection = $connection; - $this->receiveMethod = $receiveMethod; $this->buffer = new Buffer(); } @@ -99,10 +105,10 @@ public function createConsumer(PsrDestination $destination) $queue = $this->createTemporaryQueue(); $this->bind(new AmqpBind($destination, $queue, $queue->getQueueName())); - return new AmqpConsumer($this->getChannel(), $queue, $this->buffer, $this->receiveMethod); + return new AmqpConsumer($this->getChannel(), $queue, $this->buffer, $this->config['receive_method']); } - return new AmqpConsumer($this->getChannel(), $destination, $this->buffer, $this->receiveMethod); + return new AmqpConsumer($this->getChannel(), $destination, $this->buffer, $this->config['receive_method']); } /** @@ -278,6 +284,14 @@ public function close() } } + /** + * {@inheritdoc} + */ + public function setQos($prefetchSize, $prefetchCount, $global) + { + $this->getChannel()->basic_qos($prefetchSize, $prefetchCount, $global); + } + /** * @return AMQPChannel */ @@ -285,7 +299,11 @@ private function getChannel() { if (null === $this->channel) { $this->channel = $this->connection->channel(); - $this->channel->basic_qos(0, 1, false); + $this->channel->basic_qos( + $this->config['qos_prefetch_size'], + $this->config['qos_prefetch_count'], + $this->config['qos_global'] + ); } return $this->channel; diff --git a/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php b/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php index 31a1ca0ef..42ef02fbb 100644 --- a/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php +++ b/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php @@ -81,6 +81,9 @@ public static function provideConfigs() 'heartbeat' => 0, 'connection_timeout' => 3.0, 'read_write_timeout' => 3.0, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, ], ]; @@ -107,6 +110,9 @@ public static function provideConfigs() 'heartbeat' => 0, 'connection_timeout' => 3.0, 'read_write_timeout' => 3.0, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, ], ]; @@ -131,6 +137,9 @@ public static function provideConfigs() 'heartbeat' => 0, 'connection_timeout' => 3.0, 'read_write_timeout' => 3.0, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, ], ]; @@ -155,6 +164,9 @@ public static function provideConfigs() 'heartbeat' => 0, 'connection_timeout' => 3.0, 'read_write_timeout' => 3.0, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, ], ]; @@ -179,6 +191,9 @@ public static function provideConfigs() 'heartbeat' => 0, 'connection_timeout' => '2', 'read_write_timeout' => 3.0, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, ], ]; @@ -203,6 +218,9 @@ public static function provideConfigs() 'heartbeat' => 0, 'connection_timeout' => 3.0, 'read_write_timeout' => 3.0, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, ], ]; @@ -227,6 +245,9 @@ public static function provideConfigs() 'heartbeat' => 0, 'connection_timeout' => 3.0, 'read_write_timeout' => 3.0, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, ], ]; @@ -251,6 +272,9 @@ public static function provideConfigs() 'heartbeat' => 0, 'connection_timeout' => 123, 'read_write_timeout' => 321, + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, ], ]; @@ -275,6 +299,9 @@ public static function provideConfigs() '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/AmqpContextTest.php b/pkg/amqp-lib/Tests/AmqpContextTest.php index 939dcfd39..80dee492a 100644 --- a/pkg/amqp-lib/Tests/AmqpContextTest.php +++ b/pkg/amqp-lib/Tests/AmqpContextTest.php @@ -47,7 +47,7 @@ public function testShouldDeclareTopic() $topic->addFlag(AmqpTopic::FLAG_INTERNAL); $topic->addFlag(AmqpTopic::FLAG_AUTODELETE); - $session = new AmqpContext($connection, ''); + $session = new AmqpContext($connection); $session->declareTopic($topic); } @@ -77,7 +77,7 @@ public function testShouldDeleteTopic() $topic->addFlag(AmqpTopic::FLAG_IFUNUSED); $topic->addFlag(AmqpTopic::FLAG_NOWAIT); - $session = new AmqpContext($connection, ''); + $session = new AmqpContext($connection); $session->deleteTopic($topic); } @@ -115,7 +115,7 @@ public function testShouldDeclareQueue() $queue->addFlag(AmqpQueue::FLAG_EXCLUSIVE); $queue->addFlag(AmqpQueue::FLAG_NOWAIT); - $session = new AmqpContext($connection, ''); + $session = new AmqpContext($connection); $session->declareQueue($queue); } @@ -146,7 +146,7 @@ public function testShouldDeleteQueue() $queue->addFlag(AmqpQueue::FLAG_IFEMPTY); $queue->addFlag(AmqpQueue::FLAG_NOWAIT); - $session = new AmqpContext($connection, ''); + $session = new AmqpContext($connection); $session->deleteQueue($queue); } @@ -169,7 +169,7 @@ public function testBindShouldBindTopicToTopic() ->willReturn($channel) ; - $context = new AmqpContext($connection, ''); + $context = new AmqpContext($connection); $context->bind(new AmqpBind($target, $source, 'routing-key', 12345)); } @@ -192,7 +192,7 @@ public function testBindShouldBindTopicToQueue() ->willReturn($channel) ; - $context = new AmqpContext($connection, ''); + $context = new AmqpContext($connection); $context->bind(new AmqpBind($target, $source, 'routing-key', 12345)); $context->bind(new AmqpBind($source, $target, 'routing-key', 12345)); } @@ -216,7 +216,7 @@ public function testShouldUnBindTopicFromTopic() ->willReturn($channel) ; - $context = new AmqpContext($connection, ''); + $context = new AmqpContext($connection); $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345)); } @@ -239,7 +239,7 @@ public function testShouldUnBindTopicFromQueue() ->willReturn($channel) ; - $context = new AmqpContext($connection, ''); + $context = new AmqpContext($connection); $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345, ['key' => 'value'])); $context->unbind(new AmqpBind($source, $target, 'routing-key', 12345, ['key' => 'value'])); } @@ -259,7 +259,7 @@ public function testShouldCloseChannelConnection() ->willReturn($channel) ; - $context = new AmqpContext($connection, ''); + $context = new AmqpContext($connection); $context->createProducer(); $context->close(); @@ -284,10 +284,35 @@ public function testShouldPurgeQueue() ->willReturn($channel) ; - $context = new AmqpContext($connection, ''); + $context = new AmqpContext($connection); $context->purgeQueue($queue); } + public function testShouldSetQos() + { + $channel = $this->createChannelMock(); + $channel + ->expects($this->at(0)) + ->method('basic_qos') + ->with($this->identicalTo(0), $this->identicalTo(1), $this->isFalse()) + ; + $channel + ->expects($this->at(1)) + ->method('basic_qos') + ->with($this->identicalTo(123), $this->identicalTo(456), $this->isTrue()) + ; + + $connection = $this->createConnectionMock(); + $connection + ->expects($this->once()) + ->method('channel') + ->willReturn($channel) + ; + + $context = new AmqpContext($connection); + $context->setQos(123, 456, true); + } + /** * @return \PHPUnit_Framework_MockObject_MockObject|AbstractConnection */ diff --git a/pkg/amqp-lib/Tests/Spec/AmqpContextTest.php b/pkg/amqp-lib/Tests/Spec/AmqpContextTest.php index 087336d5a..5e3d8bb8e 100644 --- a/pkg/amqp-lib/Tests/Spec/AmqpContextTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpContextTest.php @@ -20,6 +20,6 @@ protected function createContext() ->willReturn($channel) ; - return new AmqpContext($con, ''); + return new AmqpContext($con); } } From 91188b91c21eee94db77abd7eb3bb42a962ff147 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Wed, 2 Aug 2017 14:38:30 +0300 Subject: [PATCH 35/76] Add method from queue-interop 0.6 that defines ttl, priority and delviery delay. --- pkg/amqp-ext/AmqpProducer.php | 48 +++++++++++++++++++++ pkg/amqp-lib/AmqpProducer.php | 48 +++++++++++++++++++++ pkg/dbal/DbalProducer.php | 48 +++++++++++++++++++++ pkg/fs/FsProducer.php | 48 +++++++++++++++++++++ pkg/gearman/GearmanProducer.php | 48 +++++++++++++++++++++ pkg/null/NullProducer.php | 60 +++++++++++++++++++++++++++ pkg/pheanstalk/PheanstalkProducer.php | 48 +++++++++++++++++++++ pkg/rdkafka/RdKafkaProducer.php | 48 +++++++++++++++++++++ pkg/redis/RedisProducer.php | 48 +++++++++++++++++++++ pkg/sqs/SqsProducer.php | 48 +++++++++++++++++++++ pkg/stomp/StompProducer.php | 48 +++++++++++++++++++++ 11 files changed, 540 insertions(+) diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index ea268de4a..de1f18ee3 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -74,4 +74,52 @@ public function send(PsrDestination $destination, PsrMessage $message) ); } } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php index 68c216960..936e996a5 100644 --- a/pkg/amqp-lib/AmqpProducer.php +++ b/pkg/amqp-lib/AmqpProducer.php @@ -69,4 +69,52 @@ public function send(PsrDestination $destination, PsrMessage $message) ); } } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/dbal/DbalProducer.php b/pkg/dbal/DbalProducer.php index 8668a68ce..99657041c 100644 --- a/pkg/dbal/DbalProducer.php +++ b/pkg/dbal/DbalProducer.php @@ -85,4 +85,52 @@ public function send(PsrDestination $destination, PsrMessage $message) throw new Exception('The transport fails to send the message due to some internal error.', null, $e); } } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/fs/FsProducer.php b/pkg/fs/FsProducer.php index a61584321..84d5a2806 100644 --- a/pkg/fs/FsProducer.php +++ b/pkg/fs/FsProducer.php @@ -56,4 +56,52 @@ public function send(PsrDestination $destination, PsrMessage $message) fwrite($file, $rawMessage); }); } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/gearman/GearmanProducer.php b/pkg/gearman/GearmanProducer.php index c7c072c76..a891ecd43 100644 --- a/pkg/gearman/GearmanProducer.php +++ b/pkg/gearman/GearmanProducer.php @@ -41,4 +41,52 @@ public function send(PsrDestination $destination, PsrMessage $message) throw new \GearmanException(sprintf('The return code is not %s (GEARMAN_SUCCESS) but %s', \GEARMAN_SUCCESS, $code)); } } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/null/NullProducer.php b/pkg/null/NullProducer.php index 307d992e8..47169a635 100644 --- a/pkg/null/NullProducer.php +++ b/pkg/null/NullProducer.php @@ -8,10 +8,70 @@ class NullProducer implements PsrProducer { + private $priority; + + private $timeToLive; + + private $deliveryDelay; + /** * {@inheritdoc} */ public function send(PsrDestination $destination, PsrMessage $message) { } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + $this->deliveryDelay = $deliveryDelay; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return $this->deliveryDelay; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + $this->priority = $priority; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return $this->priority; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + $this->timeToLive = $timeToLive; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return $this->timeToLive; + } } diff --git a/pkg/pheanstalk/PheanstalkProducer.php b/pkg/pheanstalk/PheanstalkProducer.php index 92ea44bec..d9fe8912d 100644 --- a/pkg/pheanstalk/PheanstalkProducer.php +++ b/pkg/pheanstalk/PheanstalkProducer.php @@ -51,4 +51,52 @@ public function send(PsrDestination $destination, PsrMessage $message) $message->getTimeToRun() ); } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/rdkafka/RdKafkaProducer.php b/pkg/rdkafka/RdKafkaProducer.php index b99c3300b..780f72646 100644 --- a/pkg/rdkafka/RdKafkaProducer.php +++ b/pkg/rdkafka/RdKafkaProducer.php @@ -42,4 +42,52 @@ public function send(PsrDestination $destination, PsrMessage $message) $topic = $this->producer->newTopic($destination->getTopicName(), $destination->getConf()); $topic->produce($partition, 0 /* must be 0 */, $payload, $key); } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/redis/RedisProducer.php b/pkg/redis/RedisProducer.php index 55f65b1c2..1860288d0 100644 --- a/pkg/redis/RedisProducer.php +++ b/pkg/redis/RedisProducer.php @@ -36,4 +36,52 @@ public function send(PsrDestination $destination, PsrMessage $message) $this->redis->lpush($destination->getName(), json_encode($message)); } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index 0ea55340d..f69ce65fa 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -73,4 +73,52 @@ public function send(PsrDestination $destination, PsrMessage $message) throw new \RuntimeException('Message was not sent'); } } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } diff --git a/pkg/stomp/StompProducer.php b/pkg/stomp/StompProducer.php index 17bafbebe..e5206419c 100644 --- a/pkg/stomp/StompProducer.php +++ b/pkg/stomp/StompProducer.php @@ -44,4 +44,52 @@ public function send(PsrDestination $destination, PsrMessage $message) $this->stomp->send($destination->getQueueName(), $stompMessage); } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + throw new \LogicException('Not implemented'); + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return null; + } } From 27894759474133b3708011d5c6ebf710a5f3c946 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Wed, 2 Aug 2017 14:54:46 +0300 Subject: [PATCH 36/76] upd deps --- composer.json | 4 ++-- pkg/amqp-ext/composer.json | 4 ++-- pkg/amqp-lib/composer.json | 4 ++-- pkg/async-event-dispatcher/composer.json | 2 +- pkg/dbal/composer.json | 4 ++-- pkg/enqueue/composer.json | 2 +- pkg/fs/composer.json | 4 ++-- pkg/gearman/composer.json | 4 ++-- pkg/null/composer.json | 4 ++-- pkg/pheanstalk/composer.json | 4 ++-- pkg/rdkafka/composer.json | 4 ++-- pkg/redis/composer.json | 4 ++-- pkg/sqs/composer.json | 4 ++-- pkg/stomp/composer.json | 4 ++-- 14 files changed, 26 insertions(+), 26 deletions(-) diff --git a/composer.json b/composer.json index 3d5146194..96211d62e 100644 --- a/composer.json +++ b/composer.json @@ -23,8 +23,8 @@ "enqueue/simple-client": "*@dev", "enqueue/test": "*@dev", "enqueue/async-event-dispatcher": "*@dev", - "queue-interop/queue-interop": "^0.5@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", + "queue-interop/queue-spec": "^0.6@dev", "queue-interop/amqp-interop": "^0.5@dev", "phpunit/phpunit": "^5", diff --git a/pkg/amqp-ext/composer.json b/pkg/amqp-ext/composer.json index 519b81cf5..15d4ab5da 100644 --- a/pkg/amqp-ext/composer.json +++ b/pkg/amqp-ext/composer.json @@ -13,7 +13,7 @@ "require": { "php": ">=5.6", "ext-amqp": "^1.6", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "queue-interop/amqp-interop": "^0.5@dev", "psr/log": "^1" }, @@ -22,7 +22,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "empi89/php-amqp-stubs": "*@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" diff --git a/pkg/amqp-lib/composer.json b/pkg/amqp-lib/composer.json index be9cb64e4..cb316f1b0 100644 --- a/pkg/amqp-lib/composer.json +++ b/pkg/amqp-lib/composer.json @@ -13,7 +13,7 @@ "require": { "php": ">=5.6", "php-amqplib/php-amqplib": "^2.7@dev", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "queue-interop/amqp-interop": "^0.5@dev", "psr/log": "^1" }, @@ -22,7 +22,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/async-event-dispatcher/composer.json b/pkg/async-event-dispatcher/composer.json index 122500207..3ccb9f1d9 100644 --- a/pkg/async-event-dispatcher/composer.json +++ b/pkg/async-event-dispatcher/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.6", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "symfony/event-dispatcher": "^2.8|^3" }, "require-dev": { diff --git a/pkg/dbal/composer.json b/pkg/dbal/composer.json index 6d7241de5..45e4b8992 100644 --- a/pkg/dbal/composer.json +++ b/pkg/dbal/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.6", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "doctrine/dbal": "~2.5", "psr/log": "^1" }, @@ -21,7 +21,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/enqueue/composer.json b/pkg/enqueue/composer.json index 057979af9..02efee572 100644 --- a/pkg/enqueue/composer.json +++ b/pkg/enqueue/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.6", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "enqueue/null": "^0.7@dev", "ramsey/uuid": "^2|^3.5" }, diff --git a/pkg/fs/composer.json b/pkg/fs/composer.json index edaeb297b..93218a8ce 100644 --- a/pkg/fs/composer.json +++ b/pkg/fs/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.6", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "symfony/filesystem": "^2.8|^3", "makasim/temp-file": "^0.2", "psr/log": "^1" @@ -22,7 +22,7 @@ "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", "enqueue/test": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/gearman/composer.json b/pkg/gearman/composer.json index 520a18cec..3103618d6 100644 --- a/pkg/gearman/composer.json +++ b/pkg/gearman/composer.json @@ -13,14 +13,14 @@ "require": { "php": ">=5.6", "ext-gearman": "^1.1", - "queue-interop/queue-interop": "^0.5@dev" + "queue-interop/queue-interop": "^0.6@dev" }, "require-dev": { "phpunit/phpunit": "~5.4.0", "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/null/composer.json b/pkg/null/composer.json index 529deca4d..06788367b 100644 --- a/pkg/null/composer.json +++ b/pkg/null/composer.json @@ -12,14 +12,14 @@ ], "require": { "php": ">=5.6", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "psr/log": "^1" }, "require-dev": { "phpunit/phpunit": "~5.5", "enqueue/enqueue": "^0.7@dev", "enqueue/test": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/pheanstalk/composer.json b/pkg/pheanstalk/composer.json index 25c4f2225..c709a7192 100644 --- a/pkg/pheanstalk/composer.json +++ b/pkg/pheanstalk/composer.json @@ -13,14 +13,14 @@ "require": { "php": ">=5.6", "pda/pheanstalk": "^3", - "queue-interop/queue-interop": "^0.5@dev" + "queue-interop/queue-interop": "^0.6@dev" }, "require-dev": { "phpunit/phpunit": "~5.4.0", "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/rdkafka/composer.json b/pkg/rdkafka/composer.json index 9986ce546..c111000de 100644 --- a/pkg/rdkafka/composer.json +++ b/pkg/rdkafka/composer.json @@ -13,7 +13,7 @@ "require": { "php": ">=5.6", "ext-rdkafka": "^3.0.3", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "psr/log": "^1" }, "require-dev": { @@ -21,7 +21,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "kwn/php-rdkafka-stubs": "^1.0.2" }, "autoload": { diff --git a/pkg/redis/composer.json b/pkg/redis/composer.json index 4ee0bf1a9..1b5b655f8 100644 --- a/pkg/redis/composer.json +++ b/pkg/redis/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.6", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "psr/log": "^1" }, "require-dev": { @@ -21,7 +21,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/sqs/composer.json b/pkg/sqs/composer.json index fd007abbc..666d37a51 100644 --- a/pkg/sqs/composer.json +++ b/pkg/sqs/composer.json @@ -12,7 +12,7 @@ ], "require": { "php": ">=5.6", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "aws/aws-sdk-php": "~3.26", "psr/log": "^1" }, @@ -20,7 +20,7 @@ "phpunit/phpunit": "~5.4.0", "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/stomp/composer.json b/pkg/stomp/composer.json index 5fb04fea2..b9aa146da 100644 --- a/pkg/stomp/composer.json +++ b/pkg/stomp/composer.json @@ -13,7 +13,7 @@ "require": { "php": ">=5.6", "stomp-php/stomp-php": "^4", - "queue-interop/queue-interop": "^0.5@dev", + "queue-interop/queue-interop": "^0.6@dev", "php-http/guzzle6-adapter": "^1.1", "richardfullmer/rabbitmq-management-api": "^2.0", "psr/log": "^1" @@ -23,7 +23,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.5@dev", + "queue-interop/queue-spec": "^0.6@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, From 2ec6e2689de06751612d68fe46ede8c171ea2ad1 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Wed, 2 Aug 2017 17:43:24 +0300 Subject: [PATCH 37/76] [amqp] add support of ttl and priority on producer. --- composer.json | 4 +- pkg/amqp-ext/AmqpProducer.php | 29 +++++++++-- ...ndReceivePriorityMessagesFromQueueTest.php | 40 +++++++++++++++ ...ReceiveTimeToLiveMessagesFromQueueTest.php | 38 ++++++++++++++ pkg/amqp-ext/composer.json | 6 +-- pkg/amqp-lib/AmqpContext.php | 3 +- pkg/amqp-lib/AmqpProducer.php | 29 +++++++++-- ...ndReceivePriorityMessagesFromQueueTest.php | 40 +++++++++++++++ ...ReceiveTimeToLiveMessagesFromQueueTest.php | 38 ++++++++++++++ pkg/amqp-lib/composer.json | 4 +- pkg/dbal/composer.json | 2 +- pkg/fs/composer.json | 2 +- pkg/gearman/composer.json | 2 +- pkg/null/composer.json | 2 +- pkg/pheanstalk/composer.json | 2 +- pkg/rdkafka/composer.json | 2 +- pkg/redis/composer.json | 2 +- pkg/sqs/SqsProducer.php | 19 +++++-- pkg/sqs/Tests/SqsProducerTest.php | 50 +++++++++++++++++++ pkg/sqs/composer.json | 2 +- pkg/stomp/composer.json | 2 +- 21 files changed, 286 insertions(+), 32 deletions(-) create mode 100644 pkg/amqp-ext/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php create mode 100644 pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php create mode 100644 pkg/amqp-lib/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php create mode 100644 pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php diff --git a/composer.json b/composer.json index 96211d62e..66573eaf8 100644 --- a/composer.json +++ b/composer.json @@ -24,8 +24,8 @@ "enqueue/test": "*@dev", "enqueue/async-event-dispatcher": "*@dev", "queue-interop/queue-interop": "^0.6@dev", - "queue-interop/queue-spec": "^0.6@dev", - "queue-interop/amqp-interop": "^0.5@dev", + "queue-interop/amqp-interop": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "phpunit/phpunit": "^5", "doctrine/doctrine-bundle": "~1.2", diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index de1f18ee3..72bc310a3 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -6,6 +6,7 @@ use Interop\Amqp\AmqpProducer as InteropAmqpProducer; use Interop\Amqp\AmqpQueue; use Interop\Amqp\AmqpTopic; +use Interop\Queue\DeliveryDelayNotSupportedException; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -14,6 +15,16 @@ class AmqpProducer implements InteropAmqpProducer { + /** + * @var int|null + */ + private $priority; + + /** + * @var int|float|null + */ + private $timeToLive; + /** * @var \AMQPChannel */ @@ -42,6 +53,14 @@ public function send(PsrDestination $destination, PsrMessage $message) InvalidMessageException::assertMessageInstanceOf($message, AmqpMessage::class); + if (null !== $this->priority && null === $message->getPriority()) { + $message->setPriority($this->priority); + } + + if (null !== $this->timeToLive && null === $message->getExpiration()) { + $message->setExpiration($this->timeToLive); + } + $amqpAttributes = $message->getHeaders(); if ($message->getProperties()) { @@ -80,7 +99,7 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - throw new \LogicException('Not implemented'); + throw new DeliveryDelayNotSupportedException('The provider does not support delivery delay feature'); } /** @@ -96,7 +115,7 @@ public function getDeliveryDelay() */ public function setPriority($priority) { - throw new \LogicException('Not implemented'); + $this->priority = $priority; } /** @@ -104,7 +123,7 @@ public function setPriority($priority) */ public function getPriority() { - return null; + return $this->priority; } /** @@ -112,7 +131,7 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { - throw new \LogicException('Not implemented'); + $this->timeToLive = $timeToLive; } /** @@ -120,6 +139,6 @@ public function setTimeToLive($timeToLive) */ public function getTimeToLive() { - return null; + return $this->timeToLive; } } diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php new file mode 100644 index 000000000..e8251eea0 --- /dev/null +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php @@ -0,0 +1,40 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $queue->setArguments(['x-max-priority' => 10]); + + $context->declareQueue($queue); + $context->purgeQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php new file mode 100644 index 000000000..16a67127c --- /dev/null +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php @@ -0,0 +1,38 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + $context->purgeQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-ext/composer.json b/pkg/amqp-ext/composer.json index 15d4ab5da..5329c708d 100644 --- a/pkg/amqp-ext/composer.json +++ b/pkg/amqp-ext/composer.json @@ -13,8 +13,8 @@ "require": { "php": ">=5.6", "ext-amqp": "^1.6", - "queue-interop/queue-interop": "^0.6@dev", - "queue-interop/amqp-interop": "^0.5@dev", + + "queue-interop/amqp-interop": "^0.6@dev", "psr/log": "^1" }, "require-dev": { @@ -22,7 +22,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "empi89/php-amqp-stubs": "*@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" diff --git a/pkg/amqp-lib/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php index e3f64776e..0ba8c899a 100644 --- a/pkg/amqp-lib/AmqpContext.php +++ b/pkg/amqp-lib/AmqpContext.php @@ -17,6 +17,7 @@ use Interop\Queue\PsrTopic; use PhpAmqpLib\Channel\AMQPChannel; use PhpAmqpLib\Connection\AbstractConnection; +use PhpAmqpLib\Wire\AMQPTable; class AmqpContext implements InteropAmqpContext { @@ -173,7 +174,7 @@ public function declareQueue(InteropAmqpQueue $queue) (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_EXCLUSIVE), (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_AUTODELETE), (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT), - $queue->getArguments() + $queue->getArguments() ? new AMQPTable($queue->getArguments()) : null ); } diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php index 936e996a5..981d75d49 100644 --- a/pkg/amqp-lib/AmqpProducer.php +++ b/pkg/amqp-lib/AmqpProducer.php @@ -6,6 +6,7 @@ use Interop\Amqp\AmqpProducer as InteropAmqpProducer; use Interop\Amqp\AmqpQueue as InteropAmqpQueue; use Interop\Amqp\AmqpTopic as InteropAmqpTopic; +use Interop\Queue\DeliveryDelayNotSupportedException; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -17,6 +18,16 @@ class AmqpProducer implements InteropAmqpProducer { + /** + * @var int|null + */ + private $priority; + + /** + * @var int|float|null + */ + private $timeToLive; + /** * @var AMQPChannel */ @@ -43,6 +54,14 @@ public function send(PsrDestination $destination, PsrMessage $message) InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); + if (null !== $this->priority && null === $message->getPriority()) { + $message->setPriority($this->priority); + } + + if (null !== $this->timeToLive && null === $message->getExpiration()) { + $message->setExpiration($this->timeToLive); + } + $amqpProperties = $message->getHeaders(); if ($appProperties = $message->getProperties()) { @@ -75,7 +94,7 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - throw new \LogicException('Not implemented'); + throw new DeliveryDelayNotSupportedException('The provider does not support delivery delay feature'); } /** @@ -91,7 +110,7 @@ public function getDeliveryDelay() */ public function setPriority($priority) { - throw new \LogicException('Not implemented'); + $this->priority = $priority; } /** @@ -99,7 +118,7 @@ public function setPriority($priority) */ public function getPriority() { - return null; + return $this->priority; } /** @@ -107,7 +126,7 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { - throw new \LogicException('Not implemented'); + $this->timeToLive = $timeToLive; } /** @@ -115,6 +134,6 @@ public function setTimeToLive($timeToLive) */ public function getTimeToLive() { - return null; + return $this->timeToLive; } } diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php new file mode 100644 index 000000000..881c8dd8c --- /dev/null +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php @@ -0,0 +1,40 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $queue->setArguments(['x-max-priority' => 10]); + + $context->declareQueue($queue); + $context->purgeQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php new file mode 100644 index 000000000..b62882fad --- /dev/null +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php @@ -0,0 +1,38 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + $context->purgeQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-lib/composer.json b/pkg/amqp-lib/composer.json index cb316f1b0..1241cc233 100644 --- a/pkg/amqp-lib/composer.json +++ b/pkg/amqp-lib/composer.json @@ -14,7 +14,7 @@ "php": ">=5.6", "php-amqplib/php-amqplib": "^2.7@dev", "queue-interop/queue-interop": "^0.6@dev", - "queue-interop/amqp-interop": "^0.5@dev", + "queue-interop/amqp-interop": "^0.6@dev", "psr/log": "^1" }, "require-dev": { @@ -22,7 +22,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/dbal/composer.json b/pkg/dbal/composer.json index 45e4b8992..579f59992 100644 --- a/pkg/dbal/composer.json +++ b/pkg/dbal/composer.json @@ -21,7 +21,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/fs/composer.json b/pkg/fs/composer.json index 93218a8ce..a80d9cde8 100644 --- a/pkg/fs/composer.json +++ b/pkg/fs/composer.json @@ -22,7 +22,7 @@ "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", "enqueue/test": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/gearman/composer.json b/pkg/gearman/composer.json index 3103618d6..002a0c5ea 100644 --- a/pkg/gearman/composer.json +++ b/pkg/gearman/composer.json @@ -20,7 +20,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/null/composer.json b/pkg/null/composer.json index 06788367b..8635a4288 100644 --- a/pkg/null/composer.json +++ b/pkg/null/composer.json @@ -19,7 +19,7 @@ "phpunit/phpunit": "~5.5", "enqueue/enqueue": "^0.7@dev", "enqueue/test": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/pheanstalk/composer.json b/pkg/pheanstalk/composer.json index c709a7192..16e2cda6b 100644 --- a/pkg/pheanstalk/composer.json +++ b/pkg/pheanstalk/composer.json @@ -20,7 +20,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/rdkafka/composer.json b/pkg/rdkafka/composer.json index c111000de..1737d4340 100644 --- a/pkg/rdkafka/composer.json +++ b/pkg/rdkafka/composer.json @@ -21,7 +21,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "kwn/php-rdkafka-stubs": "^1.0.2" }, "autoload": { diff --git a/pkg/redis/composer.json b/pkg/redis/composer.json index 1b5b655f8..6af42f97d 100644 --- a/pkg/redis/composer.json +++ b/pkg/redis/composer.json @@ -21,7 +21,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index 5ec17a84a..24800eb7d 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -4,12 +4,18 @@ use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; +use Interop\Queue\PriorityNotSupportedException; use Interop\Queue\PsrDestination; use Interop\Queue\PsrMessage; use Interop\Queue\PsrProducer; class SqsProducer implements PsrProducer { + /** + * @var int|float|null + */ + private $deliveryDelay; + /** * @var SqsContext */ @@ -53,9 +59,12 @@ public function send(PsrDestination $destination, PsrMessage $message) ], 'MessageBody' => $body, 'QueueUrl' => $this->context->getQueueUrl($destination), - 'DelaySeconds' => (int) $this->deliveryDelay / 1000, ]; + if (null !== $this->deliveryDelay) { + $arguments['DelaySeconds'] = (int) $this->deliveryDelay / 1000; + } + if ($message->getDelaySeconds()) { $arguments['DelaySeconds'] = $message->getDelaySeconds(); } @@ -80,7 +89,7 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - throw new \LogicException('Not implemented'); + $this->deliveryDelay = $deliveryDelay; } /** @@ -88,7 +97,7 @@ public function setDeliveryDelay($deliveryDelay) */ public function getDeliveryDelay() { - return null; + return $this->deliveryDelay; } /** @@ -96,7 +105,7 @@ public function getDeliveryDelay() */ public function setPriority($priority) { - throw new \LogicException('Not implemented'); + throw new PriorityNotSupportedException('Provider does not support priority feature'); } /** @@ -112,7 +121,7 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { - throw new \LogicException('Not implemented'); + throw new PriorityNotSupportedException('Provider does not support time to live feature'); } /** diff --git a/pkg/sqs/Tests/SqsProducerTest.php b/pkg/sqs/Tests/SqsProducerTest.php index 9be09ce78..445b9cef0 100644 --- a/pkg/sqs/Tests/SqsProducerTest.php +++ b/pkg/sqs/Tests/SqsProducerTest.php @@ -130,6 +130,56 @@ public function testShouldSendMessage() $producer->send($destination, $message); } + public function testShouldSendDelayedMessage() + { + $expectedArguments = [ + 'MessageAttributes' => [ + 'Headers' => [ + 'DataType' => 'String', + 'StringValue' => '[{"hkey":"hvaleu"},{"key":"value"}]', + ], + ], + 'MessageBody' => 'theBody', + 'QueueUrl' => 'theQueueUrl', + 'DelaySeconds' => 12345, + 'MessageDeduplicationId' => 'theDeduplicationId', + 'MessageGroupId' => 'groupId', + ]; + + $client = $this->createSqsClientMock(); + $client + ->expects($this->once()) + ->method('sendMessage') + ->with($this->identicalTo($expectedArguments)) + ->willReturn(new Result()) + ; + + $context = $this->createSqsContextMock(); + $context + ->expects($this->once()) + ->method('getQueueUrl') + ->willReturn('theQueueUrl') + ; + $context + ->expects($this->once()) + ->method('getClient') + ->will($this->returnValue($client)) + ; + + $destination = new SqsDestination('queue-name'); + $message = new SqsMessage('theBody', ['key' => 'value'], ['hkey' => 'hvaleu']); + $message->setDelaySeconds(12345); + $message->setMessageDeduplicationId('theDeduplicationId'); + $message->setMessageGroupId('groupId'); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessage('Message was not sent'); + + $producer = new SqsProducer($context); + $producer->setDeliveryDelay(5000); + $producer->send($destination, $message); + } + /** * @return \PHPUnit_Framework_MockObject_MockObject|SqsContext */ diff --git a/pkg/sqs/composer.json b/pkg/sqs/composer.json index 666d37a51..e14063309 100644 --- a/pkg/sqs/composer.json +++ b/pkg/sqs/composer.json @@ -20,7 +20,7 @@ "phpunit/phpunit": "~5.4.0", "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, diff --git a/pkg/stomp/composer.json b/pkg/stomp/composer.json index b9aa146da..996dce855 100644 --- a/pkg/stomp/composer.json +++ b/pkg/stomp/composer.json @@ -23,7 +23,7 @@ "enqueue/test": "^0.7@dev", "enqueue/enqueue": "^0.7@dev", "enqueue/null": "^0.7@dev", - "queue-interop/queue-spec": "^0.6@dev", + "queue-interop/queue-spec": "^0.5@dev", "symfony/dependency-injection": "^2.8|^3", "symfony/config": "^2.8|^3" }, From 887b2a0aae768784cc6c68d2bc4b351b7a1b7660 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Wed, 2 Aug 2017 18:05:40 +0300 Subject: [PATCH 38/76] add ttl support to fs transport. --- pkg/amqp-ext/AmqpProducer.php | 2 +- pkg/amqp-lib/AmqpProducer.php | 2 +- pkg/fs/FsConsumer.php | 9 ++++++++- pkg/fs/FsProducer.php | 17 +++++++++++++--- ...ReceiveTimeToLiveMessagesFromQueueTest.php | 20 +++++++++++++++++++ pkg/sqs/SqsProducer.php | 5 +++-- 6 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 pkg/fs/Tests/Spec/FsSendAndReceiveTimeToLiveMessagesFromQueueTest.php diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index 72bc310a3..684455ca1 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -99,7 +99,7 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - throw new DeliveryDelayNotSupportedException('The provider does not support delivery delay feature'); + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); } /** diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php index 981d75d49..5c3ba2094 100644 --- a/pkg/amqp-lib/AmqpProducer.php +++ b/pkg/amqp-lib/AmqpProducer.php @@ -94,7 +94,7 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - throw new DeliveryDelayNotSupportedException('The provider does not support delivery delay feature'); + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); } /** diff --git a/pkg/fs/FsConsumer.php b/pkg/fs/FsConsumer.php index d51f8e1e5..6dca254f2 100644 --- a/pkg/fs/FsConsumer.php +++ b/pkg/fs/FsConsumer.php @@ -89,7 +89,14 @@ public function receiveNoWait() if ($rawMessage) { try { - $this->preFetchedMessages[] = FsMessage::jsonUnserialize($rawMessage); + $fetchedMessage = FsMessage::jsonUnserialize($rawMessage); + $expireAt = $fetchedMessage->getHeader('x-expire-at'); + if ($expireAt && $expireAt - microtime(true) < 0) { + // message has expired, just drop it. + return; + } + + $this->preFetchedMessages[] = $fetchedMessage; } catch (\Exception $e) { throw new \LogicException(sprintf("Cannot decode json message '%s'", $rawMessage), null, $e); } diff --git a/pkg/fs/FsProducer.php b/pkg/fs/FsProducer.php index 84d5a2806..16f8626c1 100644 --- a/pkg/fs/FsProducer.php +++ b/pkg/fs/FsProducer.php @@ -2,8 +2,10 @@ namespace Enqueue\Fs; +use Interop\Queue\DeliveryDelayNotSupportedException; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; +use Interop\Queue\PriorityNotSupportedException; use Interop\Queue\PsrDestination; use Interop\Queue\PsrMessage; use Interop\Queue\PsrProducer; @@ -11,6 +13,11 @@ class FsProducer implements PsrProducer { + /** + * @var float|int|null + */ + private $timeToLive; + /** * @var FsContext */ @@ -41,6 +48,10 @@ public function send(PsrDestination $destination, PsrMessage $message) return; } + if (null !== $this->timeToLive) { + $message->setHeader('x-expire-at', microtime(true) + ($this->timeToLive / 1000)); + } + $rawMessage = '|'.json_encode($message); if (JSON_ERROR_NONE !== json_last_error()) { @@ -62,7 +73,7 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - throw new \LogicException('Not implemented'); + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); } /** @@ -78,7 +89,7 @@ public function getDeliveryDelay() */ public function setPriority($priority) { - throw new \LogicException('Not implemented'); + throw PriorityNotSupportedException::providerDoestNotSupportIt(); } /** @@ -94,7 +105,7 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { - throw new \LogicException('Not implemented'); + $this->timeToLive = $timeToLive; } /** diff --git a/pkg/fs/Tests/Spec/FsSendAndReceiveTimeToLiveMessagesFromQueueTest.php b/pkg/fs/Tests/Spec/FsSendAndReceiveTimeToLiveMessagesFromQueueTest.php new file mode 100644 index 000000000..3dd1697c7 --- /dev/null +++ b/pkg/fs/Tests/Spec/FsSendAndReceiveTimeToLiveMessagesFromQueueTest.php @@ -0,0 +1,20 @@ +createContext(); + } +} diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index 24800eb7d..8d69ef1cd 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -8,6 +8,7 @@ use Interop\Queue\PsrDestination; use Interop\Queue\PsrMessage; use Interop\Queue\PsrProducer; +use Interop\Queue\TimeToLiveNotSupportedException; class SqsProducer implements PsrProducer { @@ -105,7 +106,7 @@ public function getDeliveryDelay() */ public function setPriority($priority) { - throw new PriorityNotSupportedException('Provider does not support priority feature'); + throw PriorityNotSupportedException::providerDoestNotSupportIt(); } /** @@ -121,7 +122,7 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { - throw new PriorityNotSupportedException('Provider does not support time to live feature'); + throw TimeToLiveNotSupportedException::providerDoestNotSupportIt(); } /** From 0be50a3d6a895955a96a8778217cc445e821d710 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Thu, 3 Aug 2017 10:06:23 +0300 Subject: [PATCH 39/76] set routing key in consumed message --- pkg/amqp-ext/AmqpConsumer.php | 1 + pkg/amqp-lib/AmqpConsumer.php | 1 + pkg/amqp-lib/AmqpContext.php | 10 ++++++---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pkg/amqp-ext/AmqpConsumer.php b/pkg/amqp-ext/AmqpConsumer.php index 1c84a4382..4a3591d37 100644 --- a/pkg/amqp-ext/AmqpConsumer.php +++ b/pkg/amqp-ext/AmqpConsumer.php @@ -287,6 +287,7 @@ private function convertMessage(\AMQPEnvelope $extEnvelope) ); $message->setRedelivered($extEnvelope->isRedelivery()); $message->setDeliveryTag($extEnvelope->getDeliveryTag()); + $message->setRoutingKey($extEnvelope->getRoutingKey()); return $message; } diff --git a/pkg/amqp-lib/AmqpConsumer.php b/pkg/amqp-lib/AmqpConsumer.php index 90f55f32d..f08289bd9 100644 --- a/pkg/amqp-lib/AmqpConsumer.php +++ b/pkg/amqp-lib/AmqpConsumer.php @@ -196,6 +196,7 @@ private function convertMessage(LibAMQPMessage $amqpMessage) $message = new AmqpMessage($amqpMessage->getBody(), $properties, $headers); $message->setDeliveryTag($amqpMessage->delivery_info['delivery_tag']); $message->setRedelivered($amqpMessage->delivery_info['redelivered']); + $message->setRoutingKey($amqpMessage->delivery_info['routing_key']); return $message; } diff --git a/pkg/amqp-lib/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php index e3f64776e..c5f9487df 100644 --- a/pkg/amqp-lib/AmqpContext.php +++ b/pkg/amqp-lib/AmqpContext.php @@ -124,10 +124,10 @@ public function createProducer() */ public function createTemporaryQueue() { - $queue = $this->createQueue(null); - $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE); + list($name) = $this->getChannel()->queue_declare('', false, false, true, false); - $this->declareQueue($queue); + $queue = $this->createQueue($name); + $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE); return $queue; } @@ -166,7 +166,7 @@ public function deleteTopic(InteropAmqpTopic $topic) */ public function declareQueue(InteropAmqpQueue $queue) { - return $this->getChannel()->queue_declare( + list(, $messageCount) = $this->getChannel()->queue_declare( $queue->getQueueName(), (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_PASSIVE), (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_DURABLE), @@ -175,6 +175,8 @@ public function declareQueue(InteropAmqpQueue $queue) (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT), $queue->getArguments() ); + + return $messageCount; } /** From e929725ec7c41422490f321cbc734e7e0a13dba2 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Thu, 3 Aug 2017 10:07:26 +0300 Subject: [PATCH 40/76] amqp tutorial --- pkg/amqp-lib/tutorial/emit_log.php | 33 +++++++++++ pkg/amqp-lib/tutorial/emit_log_direct.php | 37 ++++++++++++ pkg/amqp-lib/tutorial/emit_log_topic.php | 37 ++++++++++++ pkg/amqp-lib/tutorial/new_task.php | 35 ++++++++++++ pkg/amqp-lib/tutorial/receive.php | 33 +++++++++++ pkg/amqp-lib/tutorial/receive_logs.php | 41 ++++++++++++++ pkg/amqp-lib/tutorial/receive_logs_direct.php | 49 ++++++++++++++++ pkg/amqp-lib/tutorial/receive_logs_topic.php | 49 ++++++++++++++++ pkg/amqp-lib/tutorial/rpc_client.php | 56 +++++++++++++++++++ pkg/amqp-lib/tutorial/rpc_server.php | 52 +++++++++++++++++ pkg/amqp-lib/tutorial/send.php | 26 +++++++++ pkg/amqp-lib/tutorial/worker.php | 38 +++++++++++++ 12 files changed, 486 insertions(+) create mode 100644 pkg/amqp-lib/tutorial/emit_log.php create mode 100644 pkg/amqp-lib/tutorial/emit_log_direct.php create mode 100644 pkg/amqp-lib/tutorial/emit_log_topic.php create mode 100644 pkg/amqp-lib/tutorial/new_task.php create mode 100644 pkg/amqp-lib/tutorial/receive.php create mode 100644 pkg/amqp-lib/tutorial/receive_logs.php create mode 100644 pkg/amqp-lib/tutorial/receive_logs_direct.php create mode 100644 pkg/amqp-lib/tutorial/receive_logs_topic.php create mode 100644 pkg/amqp-lib/tutorial/rpc_client.php create mode 100644 pkg/amqp-lib/tutorial/rpc_server.php create mode 100644 pkg/amqp-lib/tutorial/send.php create mode 100644 pkg/amqp-lib/tutorial/worker.php diff --git a/pkg/amqp-lib/tutorial/emit_log.php b/pkg/amqp-lib/tutorial/emit_log.php new file mode 100644 index 000000000..bc9fd4c2b --- /dev/null +++ b/pkg/amqp-lib/tutorial/emit_log.php @@ -0,0 +1,33 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$topic = $context->createTopic('logs'); +$topic->setType(AmqpTopic::TYPE_FANOUT); + +$context->declareTopic($topic); + +$data = implode(' ', array_slice($argv, 1)); +if (empty($data)) { + $data = 'info: Hello World!'; +} +$message = $context->createMessage($data); + +$context->createProducer()->send($topic, $message); + +echo ' [x] Sent ', $data, "\n"; + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/emit_log_direct.php b/pkg/amqp-lib/tutorial/emit_log_direct.php new file mode 100644 index 000000000..87e890854 --- /dev/null +++ b/pkg/amqp-lib/tutorial/emit_log_direct.php @@ -0,0 +1,37 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$topic = $context->createTopic('direct_logs'); +$topic->setType(AmqpTopic::TYPE_DIRECT); + +$context->declareTopic($topic); + +$severity = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'info'; + +$data = implode(' ', array_slice($argv, 2)); +if (empty($data)) { + $data = 'Hello World!'; +} + +$message = $context->createMessage($data); +$message->setRoutingKey($severity); + +$context->createProducer()->send($topic, $message); + +echo ' [x] Sent ',$severity,':',$data," \n"; + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/emit_log_topic.php b/pkg/amqp-lib/tutorial/emit_log_topic.php new file mode 100644 index 000000000..ab181865c --- /dev/null +++ b/pkg/amqp-lib/tutorial/emit_log_topic.php @@ -0,0 +1,37 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$topic = $context->createTopic('topic_logs'); +$topic->setType(AmqpTopic::TYPE_TOPIC); + +$context->declareTopic($topic); + +$routing_key = isset($argv[1]) && !empty($argv[1]) ? $argv[1] : 'anonymous.info'; + +$data = implode(' ', array_slice($argv, 2)); +if (empty($data)) { + $data = 'Hello World!'; +} + +$message = $context->createMessage($data); +$message->setRoutingKey($routing_key); + +$context->createProducer()->send($topic, $message); + +echo ' [x] Sent ',$routing_key,':',$data," \n"; + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/new_task.php b/pkg/amqp-lib/tutorial/new_task.php new file mode 100644 index 000000000..5c3c836f8 --- /dev/null +++ b/pkg/amqp-lib/tutorial/new_task.php @@ -0,0 +1,35 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$queue = $context->createQueue('task_queue'); +$queue->addFlag(AmqpQueue::FLAG_DURABLE); + +$context->declareQueue($queue); + +$data = implode(' ', array_slice($argv, 1)); +if (empty($data)) { + $data = 'Hello World!'; +} +$message = $context->createMessage($data); +$message->setDeliveryMode(AmqpMessage::DELIVERY_MODE_PERSISTENT); + +$context->createProducer()->send($queue, $message); + +echo ' [x] Sent ', $data, "\n"; + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/receive.php b/pkg/amqp-lib/tutorial/receive.php new file mode 100644 index 000000000..337421020 --- /dev/null +++ b/pkg/amqp-lib/tutorial/receive.php @@ -0,0 +1,33 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'receive_method' => 'basic_consume', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$queue = $context->createQueue('hello'); +$context->declareQueue($queue); + +$consumer = $context->createConsumer($queue); +$consumer->addFlag(AmqpConsumer::FLAG_NOACK); + +echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; + +while (true) { + if ($message = $consumer->receive()) { + echo ' [x] Received ', $message->getBody(), "\n"; + } +} + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/receive_logs.php b/pkg/amqp-lib/tutorial/receive_logs.php new file mode 100644 index 000000000..bf68bf1fb --- /dev/null +++ b/pkg/amqp-lib/tutorial/receive_logs.php @@ -0,0 +1,41 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'receive_method' => 'basic_consume', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$topic = $context->createTopic('logs'); +$topic->setType(AmqpTopic::TYPE_FANOUT); + +$context->declareTopic($topic); + +$queue = $context->createTemporaryQueue(); + +$context->bind(new AmqpBind($topic, $queue)); + +$consumer = $context->createConsumer($queue); +$consumer->addFlag(AmqpConsumer::FLAG_NOACK); + +echo ' [*] Waiting for logs. To exit press CTRL+C', "\n"; + +while (true) { + if ($message = $consumer->receive()) { + echo ' [x] ', $message->getBody(), "\n"; + } +} + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/receive_logs_direct.php b/pkg/amqp-lib/tutorial/receive_logs_direct.php new file mode 100644 index 000000000..699d5108f --- /dev/null +++ b/pkg/amqp-lib/tutorial/receive_logs_direct.php @@ -0,0 +1,49 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'receive_method' => 'basic_consume', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$topic = $context->createTopic('direct_logs'); +$topic->setType(AmqpTopic::TYPE_DIRECT); + +$context->declareTopic($topic); + +$queue = $context->createTemporaryQueue(); + +$severities = array_slice($argv, 1); +if (empty($severities)) { + file_put_contents('php://stderr', "Usage: $argv[0] [info] [warning] [error]\n"); + exit(1); +} + +foreach ($severities as $severity) { + $context->bind(new AmqpBind($topic, $queue, $severity)); +} + +$consumer = $context->createConsumer($queue); +$consumer->addFlag(AmqpConsumer::FLAG_NOACK); + +echo ' [*] Waiting for logs. To exit press CTRL+C', "\n"; + +while (true) { + if ($message = $consumer->receive()) { + echo ' [x] '.$message->getRoutingKey().':'.$message->getBody()."\n"; + } +} + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/receive_logs_topic.php b/pkg/amqp-lib/tutorial/receive_logs_topic.php new file mode 100644 index 000000000..a149be84c --- /dev/null +++ b/pkg/amqp-lib/tutorial/receive_logs_topic.php @@ -0,0 +1,49 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'receive_method' => 'basic_consume', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$topic = $context->createTopic('topic_logs'); +$topic->setType(AmqpTopic::TYPE_TOPIC); + +$context->declareTopic($topic); + +$queue = $context->createTemporaryQueue(); + +$binding_keys = array_slice($argv, 1); +if (empty($binding_keys)) { + file_put_contents('php://stderr', "Usage: $argv[0] [binding_key]\n"); + exit(1); +} + +foreach ($binding_keys as $binding_key) { + $context->bind(new AmqpBind($topic, $queue, $binding_key)); +} + +$consumer = $context->createConsumer($queue); +$consumer->addFlag(AmqpConsumer::FLAG_NOACK); + +echo ' [*] Waiting for logs. To exit press CTRL+C', "\n"; + +while (true) { + if ($message = $consumer->receive()) { + echo ' [x] '.$message->getRoutingKey().':'.$message->getBody()."\n"; + } +} + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/rpc_client.php b/pkg/amqp-lib/tutorial/rpc_client.php new file mode 100644 index 000000000..9c34510dd --- /dev/null +++ b/pkg/amqp-lib/tutorial/rpc_client.php @@ -0,0 +1,56 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'receive_method' => 'basic_consume', +]; + +class FibonacciRpcClient +{ + /** @var \Interop\Amqp\AmqpContext */ + private $context; + + /** @var \Interop\Amqp\AmqpQueue */ + private $callback_queue; + + public function __construct(array $config) + { + $this->context = (new AmqpConnectionFactory($config))->createContext(); + $this->callback_queue = $this->context->createTemporaryQueue(); + } + + public function call($n) + { + $corr_id = uniqid(); + + $message = $this->context->createMessage((string) $n); + $message->setCorrelationId($corr_id); + $message->setReplyTo($this->callback_queue->getQueueName()); + + $this->context->createProducer()->send( + $this->context->createQueue('rpc_queue'), + $message + ); + + $consumer = $this->context->createConsumer($this->callback_queue); + + while (true) { + if ($message = $consumer->receive()) { + if ($message->getCorrelationId() == $corr_id) { + return (int) ($message->getBody()); + } + } + } + } +} + +$fibonacci_rpc = new FibonacciRpcClient($config); +$response = $fibonacci_rpc->call(30); +echo ' [.] Got ', $response, "\n"; diff --git a/pkg/amqp-lib/tutorial/rpc_server.php b/pkg/amqp-lib/tutorial/rpc_server.php new file mode 100644 index 000000000..3ad25fbe2 --- /dev/null +++ b/pkg/amqp-lib/tutorial/rpc_server.php @@ -0,0 +1,52 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'receive_method' => 'basic_consume', +]; + +function fib($n) +{ + if ($n == 0) { + return 0; + } + if ($n == 1) { + return 1; + } + return fib($n - 1) + fib($n - 2); +} + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); +$context->setQos(0, 1, false); + +$rpc_queue = $context->createQueue('rpc_queue'); +$context->declareQueue($rpc_queue); + +$consumer = $context->createConsumer($rpc_queue); + +echo " [x] Awaiting RPC requests\n"; + +while (true) { + if ($req = $consumer->receive()) { + $n = (int) ($req->getBody()); + echo ' [.] fib(', $n, ")\n"; + + $msg = $context->createMessage((string) fib($n)); + $msg->setCorrelationId($req->getCorrelationId()); + + $reply_queue = $context->createQueue($req->getReplyTo()); + $context->createProducer()->send($reply_queue, $msg); + + $consumer->acknowledge($req); + } +} + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/send.php b/pkg/amqp-lib/tutorial/send.php new file mode 100644 index 000000000..5f1d89b62 --- /dev/null +++ b/pkg/amqp-lib/tutorial/send.php @@ -0,0 +1,26 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); + +$queue = $context->createQueue('hello'); +$context->declareQueue($queue); + +$message = $context->createMessage('Hello World!'); + +$context->createProducer()->send($queue, $message); + +echo " [x] Sent 'Hello World!'\n"; + +$context->close(); diff --git a/pkg/amqp-lib/tutorial/worker.php b/pkg/amqp-lib/tutorial/worker.php new file mode 100644 index 000000000..3f908b6a6 --- /dev/null +++ b/pkg/amqp-lib/tutorial/worker.php @@ -0,0 +1,38 @@ + 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'pass' => 'guest', + 'receive_method' => 'basic_consume', +]; + +$connection = new AmqpConnectionFactory($config); +$context = $connection->createContext(); +$context->setQos(0, 1, false); + +$queue = $context->createQueue('task_queue'); +$queue->addFlag(AmqpQueue::FLAG_DURABLE); + +$context->declareQueue($queue); + +$consumer = $context->createConsumer($queue); + +echo ' [*] Waiting for messages. To exit press CTRL+C', "\n"; + +while (true) { + if ($message = $consumer->receive()) { + echo ' [x] Received ', $message->getBody(), "\n"; + sleep(substr_count($message->getBody(), '.')); + echo ' [x] Done', "\n"; + $consumer->acknowledge($message); + } +} + +$context->close(); From 1186af16251ebd613e88de264c3ef6cc1b6334c5 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Thu, 3 Aug 2017 11:19:52 +0300 Subject: [PATCH 41/76] cs fix --- pkg/amqp-lib/tutorial/rpc_server.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/amqp-lib/tutorial/rpc_server.php b/pkg/amqp-lib/tutorial/rpc_server.php index 3ad25fbe2..9e848dce0 100644 --- a/pkg/amqp-lib/tutorial/rpc_server.php +++ b/pkg/amqp-lib/tutorial/rpc_server.php @@ -17,9 +17,11 @@ function fib($n) if ($n == 0) { return 0; } + if ($n == 1) { return 1; } + return fib($n - 1) + fib($n - 2); } From 828f497728e6f5567a7fbbc1128484fd2edc1ddc Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 3 Aug 2017 14:03:22 +0300 Subject: [PATCH 42/76] retry fragile tests. --- .../RdKafkaSendToAndReceiveFromTopicTest.php | 1 + .../Functional/SqsConsumptionUseCasesTest.php | 8 ++++ ...dAndReceiveDelayedMessageFromQueueTest.php | 4 ++ pkg/test/RetryTrait.php | 44 +++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 pkg/test/RetryTrait.php diff --git a/pkg/rdkafka/Tests/Spec/RdKafkaSendToAndReceiveFromTopicTest.php b/pkg/rdkafka/Tests/Spec/RdKafkaSendToAndReceiveFromTopicTest.php index 808721681..4bb32d7a5 100644 --- a/pkg/rdkafka/Tests/Spec/RdKafkaSendToAndReceiveFromTopicTest.php +++ b/pkg/rdkafka/Tests/Spec/RdKafkaSendToAndReceiveFromTopicTest.php @@ -8,6 +8,7 @@ /** * @group functional + * @retry 5 */ class RdKafkaSendToAndReceiveFromTopicTest extends SendToAndReceiveFromTopicSpec { diff --git a/pkg/sqs/Tests/Functional/SqsConsumptionUseCasesTest.php b/pkg/sqs/Tests/Functional/SqsConsumptionUseCasesTest.php index 35e978c23..490c70ebf 100644 --- a/pkg/sqs/Tests/Functional/SqsConsumptionUseCasesTest.php +++ b/pkg/sqs/Tests/Functional/SqsConsumptionUseCasesTest.php @@ -9,6 +9,7 @@ use Enqueue\Consumption\QueueConsumer; use Enqueue\Consumption\Result; use Enqueue\Sqs\SqsContext; +use Enqueue\Test\RetryTrait; use Enqueue\Test\SqsExtension; use Interop\Queue\PsrContext; use Interop\Queue\PsrMessage; @@ -18,6 +19,7 @@ class SqsConsumptionUseCasesTest extends TestCase { use SqsExtension; + use RetryTrait; /** * @var SqsContext @@ -43,6 +45,9 @@ protected function setUp() } } + /** + * @retry 5 + */ public function testConsumeOneMessageAndExit() { $queue = $this->context->createQueue('enqueue_test_queue'); @@ -64,6 +69,9 @@ public function testConsumeOneMessageAndExit() $this->assertEquals(__METHOD__, $processor->lastProcessedMessage->getBody()); } + /** + * @retry 5 + */ public function testConsumeOneMessageAndSendReplyExit() { $queue = $this->context->createQueue('enqueue_test_queue'); diff --git a/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php b/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php index 7d7b30aae..9fd3e96b8 100644 --- a/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php +++ b/pkg/sqs/Tests/Spec/SqsSendAndReceiveDelayedMessageFromQueueTest.php @@ -4,14 +4,18 @@ use Enqueue\Sqs\SqsConnectionFactory; use Enqueue\Sqs\SqsContext; +use Enqueue\Test\RetryTrait; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; /** * @group functional + * @retry 5 */ class SqsSendAndReceiveDelayedMessageFromQueueTest extends SendAndReceiveDelayedMessageFromQueueSpec { + use RetryTrait; + /** * {@inheritdoc} */ diff --git a/pkg/test/RetryTrait.php b/pkg/test/RetryTrait.php new file mode 100644 index 000000000..27ef3f5e5 --- /dev/null +++ b/pkg/test/RetryTrait.php @@ -0,0 +1,44 @@ +getNumberOfRetries(); + for ($i = 0; $i < $numberOfRetires; ++$i) { + try { + parent::runBare(); + + return; + } catch (\Exception $e) { + // last one thrown below + } + } + + if ($e) { + throw $e; + } + } + + /** + * @return int + */ + private function getNumberOfRetries() + { + $annotations = $this->getAnnotations(); + + if (isset($annotations['method']['retry'])) { + return $annotations['method']['retry']; + } + + if (isset($annotations['class']['retry'][0])) { + return $annotations['class']['retry'][0]; + } + + return 1; + } +} From 79ff3b35847ef01148c7de0dc4fb02a751b9b3e4 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 3 Aug 2017 14:20:08 +0300 Subject: [PATCH 43/76] [client] Use default as router topic. It fixes issues with fs transport when client's default config is used. --- pkg/enqueue-bundle/DependencyInjection/Configuration.php | 2 +- .../Tests/Unit/DependencyInjection/ConfigurationTest.php | 2 +- pkg/simple-client/SimpleClientContainerExtension.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/enqueue-bundle/DependencyInjection/Configuration.php b/pkg/enqueue-bundle/DependencyInjection/Configuration.php index 7fe7b13db..c02b0c508 100644 --- a/pkg/enqueue-bundle/DependencyInjection/Configuration.php +++ b/pkg/enqueue-bundle/DependencyInjection/Configuration.php @@ -44,7 +44,7 @@ public function getConfigTreeBuilder() ->booleanNode('traceable_producer')->defaultFalse()->end() ->scalarNode('prefix')->defaultValue('enqueue')->end() ->scalarNode('app_name')->defaultValue('app')->end() - ->scalarNode('router_topic')->defaultValue('router')->cannotBeEmpty()->end() + ->scalarNode('router_topic')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() ->scalarNode('router_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() ->scalarNode('router_processor')->defaultValue('enqueue.client.router_processor')->end() ->scalarNode('default_processor_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() diff --git a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php index a5e99b40a..bd3162a43 100644 --- a/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php +++ b/pkg/enqueue-bundle/Tests/Unit/DependencyInjection/ConfigurationTest.php @@ -145,7 +145,7 @@ public function testShouldSetDefaultConfigurationForClient() 'prefix' => 'enqueue', 'app_name' => 'app', 'router_processor' => 'enqueue.client.router_processor', - 'router_topic' => 'router', + 'router_topic' => 'default', 'router_queue' => 'default', 'default_processor_queue' => 'default', 'traceable_producer' => false, diff --git a/pkg/simple-client/SimpleClientContainerExtension.php b/pkg/simple-client/SimpleClientContainerExtension.php index 7fea6f03b..f10a7b186 100644 --- a/pkg/simple-client/SimpleClientContainerExtension.php +++ b/pkg/simple-client/SimpleClientContainerExtension.php @@ -172,7 +172,7 @@ private function createConfiguration() ->arrayNode('client')->children() ->scalarNode('prefix')->defaultValue('enqueue')->end() ->scalarNode('app_name')->defaultValue('app')->end() - ->scalarNode('router_topic')->defaultValue('router')->cannotBeEmpty()->end() + ->scalarNode('router_topic')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() ->scalarNode('router_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() ->scalarNode('default_processor_queue')->defaultValue(Config::DEFAULT_PROCESSOR_QUEUE_NAME)->cannotBeEmpty()->end() ->integerNode('redelivered_delay_time')->min(0)->defaultValue(0)->end() From 9a1f0c55f1ea33c2c90b99eaa1802f0aedcbfc2b Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 3 Aug 2017 15:02:58 +0300 Subject: [PATCH 44/76] add docs. --- docs/transport/amqp.md | 38 ++++++++++++++++++++++++++++++++++++ docs/transport/amqp_lib.md | 38 ++++++++++++++++++++++++++++++++++++ docs/transport/filesystem.md | 17 ++++++++++++++++ docs/transport/sqs.md | 17 ++++++++++++++++ 4 files changed, 110 insertions(+) diff --git a/docs/transport/amqp.md b/docs/transport/amqp.md index f28e45806..97ea37fdf 100644 --- a/docs/transport/amqp.md +++ b/docs/transport/amqp.md @@ -10,6 +10,8 @@ Build on top of [php amqp extension](https://github.com/pdezwart/php-amqp). * [Bind queue to topic](#bind-queue-to-topic) * [Send message to topic](#send-message-to-topic) * [Send message to queue](#send-message-to-queue) +* [Send priority message](#send-priority-message) +* [Send expiration message](#send-expiration-message) * [Consume message](#consume-message) * [Purge queue messages](#purge-queue-messages) @@ -125,6 +127,42 @@ $message = $psrContext->createMessage('Hello world!'); $psrContext->createProducer()->send($fooQueue, $message); ``` +## Send priority message + +```php +createQueue('foo'); +$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE); +$fooQueue->setArguments(['x-max-priority' => 10]); +$psrContext->declareQueue($fooQueue); + +$message = $psrContext->createMessage('Hello world!'); + +$psrContext->createProducer() + ->setPriority(5) // the higher priority the sooner a message gets to a consumer + // + ->send($fooQueue, $message) +; +``` + +## Send expiration message + +```php +createMessage('Hello world!'); + +$psrContext->createProducer() + ->setTimeToLive(60000) // 60 sec + // + ->send($fooQueue, $message) +; +``` + ## Consume message: ```php diff --git a/docs/transport/amqp_lib.md b/docs/transport/amqp_lib.md index 1cbf41abc..b087c1b47 100644 --- a/docs/transport/amqp_lib.md +++ b/docs/transport/amqp_lib.md @@ -10,6 +10,8 @@ Build on top of [php amqp lib](https://github.com/php-amqplib/php-amqplib). * [Bind queue to topic](#bind-queue-to-topic) * [Send message to topic](#send-message-to-topic) * [Send message to queue](#send-message-to-queue) +* [Send priority message](#send-priority-message) +* [Send expiration message](#send-expiration-message) * [Consume message](#consume-message) * [Purge queue messages](#purge-queue-messages) @@ -125,6 +127,42 @@ $message = $psrContext->createMessage('Hello world!'); $psrContext->createProducer()->send($fooQueue, $message); ``` +## Send priority message + +```php +createQueue('foo'); +$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE); +$fooQueue->setArguments(['x-max-priority' => 10]); +$psrContext->declareQueue($fooQueue); + +$message = $psrContext->createMessage('Hello world!'); + +$psrContext->createProducer() + ->setPriority(5) // the higher priority the sooner a message gets to a consumer + // + ->send($fooQueue, $message) +; +``` + +## Send expiration message + +```php +createMessage('Hello world!'); + +$psrContext->createProducer() + ->setTimeToLive(60000) // 60 sec + // + ->send($fooQueue, $message) +; +``` + ## Consume message: ```php diff --git a/docs/transport/filesystem.md b/docs/transport/filesystem.md index 34a7a5146..3b529eadc 100644 --- a/docs/transport/filesystem.md +++ b/docs/transport/filesystem.md @@ -9,6 +9,7 @@ A message is a line inside the file. * [Create context](#create-context) * [Send message to topic](#send-message-to-topic) * [Send message to queue](#send-message-to-queue) +* [Send expiration message](#send-expiration-message) * [Consume message](#consume-message) * [Purge queue messages](#purge-queue-messages) @@ -72,6 +73,22 @@ $message = $psrContext->createMessage('Hello world!'); $psrContext->createProducer()->send($fooQueue, $message); ``` +## Send expiration message + +```php +createQueue('aQueue'); +$message = $psrContext->createMessage('Hello world!'); + +$psrContext->createProducer() + ->setTimeToLive(60000) // 60 sec + // + ->send($fooQueue, $message) +; +``` + ## Consume message: ```php diff --git a/docs/transport/sqs.md b/docs/transport/sqs.md index 86e3971e5..b799b1f21 100644 --- a/docs/transport/sqs.md +++ b/docs/transport/sqs.md @@ -7,6 +7,7 @@ It uses internally official [aws sdk library](https://packagist.org/packages/aws * [Create context](#create-context) * [Declare queue](#decalre-queue) * [Send message to queue](#send-message-to-queue) +* [Send delay message](#send-delay-message) * [Consume message](#consume-message) * [Purge queue messages](#purge-queue-messages) @@ -58,6 +59,22 @@ $message = $psrContext->createMessage('Hello world!'); $psrContext->createProducer()->send($fooQueue, $message); ``` +## Send delay message + +```php +createQueue('foo'); +$message = $psrContext->createMessage('Hello world!'); + +$psrContext->createProducer() + ->setDeliveryDelay(60000) // 60 sec + + ->send($fooQueue, $message) +; +``` + ## Consume message: ```php From 918bff60ed36397ca42faf552e71573185e1d0f5 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 3 Aug 2017 15:05:26 +0300 Subject: [PATCH 45/76] producer setters must return this. --- pkg/amqp-ext/AmqpProducer.php | 4 ++++ pkg/amqp-lib/AmqpProducer.php | 4 ++++ pkg/fs/FsProducer.php | 2 ++ pkg/sqs/SqsProducer.php | 2 ++ 4 files changed, 12 insertions(+) diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index 684455ca1..4ed1845c9 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -116,6 +116,8 @@ public function getDeliveryDelay() public function setPriority($priority) { $this->priority = $priority; + + return $this; } /** @@ -132,6 +134,8 @@ public function getPriority() public function setTimeToLive($timeToLive) { $this->timeToLive = $timeToLive; + + return $this; } /** diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php index 5c3ba2094..c5d8c0927 100644 --- a/pkg/amqp-lib/AmqpProducer.php +++ b/pkg/amqp-lib/AmqpProducer.php @@ -111,6 +111,8 @@ public function getDeliveryDelay() public function setPriority($priority) { $this->priority = $priority; + + return $this; } /** @@ -127,6 +129,8 @@ public function getPriority() public function setTimeToLive($timeToLive) { $this->timeToLive = $timeToLive; + + return $this; } /** diff --git a/pkg/fs/FsProducer.php b/pkg/fs/FsProducer.php index 16f8626c1..5ab27db22 100644 --- a/pkg/fs/FsProducer.php +++ b/pkg/fs/FsProducer.php @@ -106,6 +106,8 @@ public function getPriority() public function setTimeToLive($timeToLive) { $this->timeToLive = $timeToLive; + + return $this; } /** diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index 8d69ef1cd..ad334e100 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -91,6 +91,8 @@ public function send(PsrDestination $destination, PsrMessage $message) public function setDeliveryDelay($deliveryDelay) { $this->deliveryDelay = $deliveryDelay; + + return $this; } /** From a24f1ed45414e7ae83c96ef8bb5dd884510518d5 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Thu, 3 Aug 2017 15:55:09 +0300 Subject: [PATCH 46/76] fix retry --- pkg/test/RetryTrait.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/test/RetryTrait.php b/pkg/test/RetryTrait.php index 27ef3f5e5..cc8c377e4 100644 --- a/pkg/test/RetryTrait.php +++ b/pkg/test/RetryTrait.php @@ -14,6 +14,12 @@ public function runBare() parent::runBare(); return; + } catch (\PHPUnit_Framework_IncompleteTestError $e) { + throw $e; + } catch (\PHPUnit_Framework_SkippedTestError $e) { + throw $e; + } catch (\Throwable $e) { + // last one thrown below } catch (\Exception $e) { // last one thrown below } From afd0d2428095d418c0b8a2b276f2f499519c1b16 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Thu, 3 Aug 2017 16:09:40 +0300 Subject: [PATCH 47/76] delay strategy --- .../Client/Amqp/DelayPluginDelayStrategy.php | 43 +++++++++++++++++ pkg/enqueue/Client/Amqp/DelayStrategy.php | 17 +++++++ pkg/enqueue/Client/Amqp/DlxDelayStrategy.php | 47 +++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 pkg/enqueue/Client/Amqp/DelayPluginDelayStrategy.php create mode 100644 pkg/enqueue/Client/Amqp/DelayStrategy.php create mode 100644 pkg/enqueue/Client/Amqp/DlxDelayStrategy.php diff --git a/pkg/enqueue/Client/Amqp/DelayPluginDelayStrategy.php b/pkg/enqueue/Client/Amqp/DelayPluginDelayStrategy.php new file mode 100644 index 000000000..b4959b5fa --- /dev/null +++ b/pkg/enqueue/Client/Amqp/DelayPluginDelayStrategy.php @@ -0,0 +1,43 @@ +getDelay(); + + if ($dest instanceof AmqpTopic) { + $delayTopic = $context->createTopic($dest->getTopicName().'.x.delayed'); + $delayTopic->setType('x-delayed-message'); + $delayTopic->addFlag(AmqpTopic::FLAG_DURABLE); + $delayTopic->setArgument('x-delayed-type', AmqpTopic::TYPE_DIRECT); + + $context->declareTopic($delayTopic); + $context->bind(new AmqpBind($dest, $delayTopic)); + } elseif ($dest instanceof AmqpQueue) { + $delayTopic = $context->createTopic($dest->getQueueName().'.delayed'); + $delayTopic->setType('x-delayed-message'); + $delayTopic->addFlag(AmqpTopic::FLAG_DURABLE); + $delayTopic->setArgument('x-delayed-type', AmqpTopic::TYPE_DIRECT); + + $context->declareTopic($delayTopic); + $context->bind(new AmqpBind($delayTopic, $dest, $dest->getQueueName())); + } else { + throw new \LogicException(); + } + + $delayMessage = $context->createMessage($message->getBody(), $message->getProperties(), $message->getHeaders()); + $delayMessage->setProperty('x-delay', (string) ($delaySec * 1000)); + + $context->createProducer()->send($delayTopic, $delayMessage); + } +} diff --git a/pkg/enqueue/Client/Amqp/DelayStrategy.php b/pkg/enqueue/Client/Amqp/DelayStrategy.php new file mode 100644 index 000000000..de222190e --- /dev/null +++ b/pkg/enqueue/Client/Amqp/DelayStrategy.php @@ -0,0 +1,17 @@ +getDelay(); + + if ($dest instanceof AmqpTopic) { + $delayQueue = $context->createQueue($dest->getTopicName().'.'.$delaySec.'.x.delayed'); + $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE); + $delayQueue->setArgument('x-dead-letter-exchange', $dest->getTopicName()); + } elseif ($dest instanceof AmqpQueue) { + $delayQueue = $context->createQueue($dest->getQueueName().'.'.$delaySec.'.delayed'); + $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE); + $delayQueue->setArgument('x-dead-letter-exchange', ''); + $delayQueue->setArgument('x-dead-letter-routing-key', $dest->getQueueName()); + } else { + throw new \LogicException(); + } + + $context->declareQueue($delayQueue); + + $properties = $message->getProperties(); + + // The x-death header must be removed because of the bug in RabbitMQ. + // It was reported that the bug is fixed since 3.5.4 but I tried with 3.6.1 and the bug still there. + // https://github.com/rabbitmq/rabbitmq-server/issues/216 + unset($properties['x-death']); + + $delayMessage = $context->createMessage($message->getBody(), $properties, $message->getHeaders()); + $delayMessage->setExpiration((string) ($delaySec * 1000)); + + $context->createProducer()->send($delayQueue, $delayMessage); + } +} From 700dc96a495063367f32186fd31448d03bce79e8 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 4 Aug 2017 14:36:06 +0300 Subject: [PATCH 48/76] Amqp bunny --- composer.json | 5 + docs/index.md | 2 +- docs/transport/amqp_bunny.md | 195 +++++++++++ phpunit.xml.dist | 4 + pkg/amqp-bunny/.gitignore | 6 + pkg/amqp-bunny/.travis.yml | 21 ++ pkg/amqp-bunny/AmqpConnectionFactory.php | 159 +++++++++ pkg/amqp-bunny/AmqpConsumer.php | 299 ++++++++++++++++ pkg/amqp-bunny/AmqpContext.php | 324 ++++++++++++++++++ pkg/amqp-bunny/AmqpProducer.php | 141 ++++++++ pkg/amqp-bunny/Buffer.php | 43 +++ pkg/amqp-bunny/LICENSE | 20 ++ pkg/amqp-bunny/README.md | 26 ++ .../Symfony/AmqpBunnyTransportFactory.php | 140 ++++++++ .../RabbitMqAmqpBunnyTransportFactory.php | 53 +++ .../Tests/AmqpConnectionFactoryConfigTest.php | 235 +++++++++++++ pkg/amqp-bunny/Tests/AmqpConsumerTest.php | 242 +++++++++++++ pkg/amqp-bunny/Tests/AmqpContextTest.php | 245 +++++++++++++ pkg/amqp-bunny/Tests/AmqpProducerTest.php | 153 +++++++++ pkg/amqp-bunny/Tests/BufferTest.php | 64 ++++ .../Tests/Spec/AmqpConnectionFactoryTest.php | 14 + pkg/amqp-bunny/Tests/Spec/AmqpContextTest.php | 17 + ...ndReceivePriorityMessagesFromQueueTest.php | 40 +++ ...ReceiveTimeToLiveMessagesFromQueueTest.php | 38 ++ .../AmqpSendToAndReceiveFromQueueTest.php | 38 ++ .../AmqpSendToAndReceiveFromTopicTest.php | 40 +++ ...mqpSendToAndReceiveNoWaitFromQueueTest.php | 38 ++ ...mqpSendToAndReceiveNoWaitFromTopicTest.php | 40 +++ ...iveFromQueueWithBasicConsumeMethodTest.php | 61 ++++ ...ReceiveFromQueueWithBasicGetMethodTest.php | 57 +++ ...ndToTopicAndReceiveNoWaitFromQueueTest.php | 57 +++ .../Symfony/AmqpBunnyTransportFactoryTest.php | 218 ++++++++++++ .../RabbitMqAmqpBunnyTransportFactoryTest.php | 137 ++++++++ pkg/amqp-bunny/composer.json | 42 +++ pkg/amqp-bunny/phpunit.xml.dist | 30 ++ pkg/amqp-ext/AmqpConnectionFactory.php | 4 + pkg/amqp-ext/DeliveryMode.php | 9 - pkg/amqp-ext/README.md | 2 +- .../Tests/AmqpConnectionFactoryConfigTest.php | 19 + pkg/amqp-lib/AmqpConnectionFactory.php | 4 + pkg/amqp-lib/AmqpContext.php | 2 +- pkg/amqp-lib/README.md | 26 ++ .../Tests/AmqpConnectionFactoryConfigTest.php | 27 ++ .../DsnToConnectionFactoryFunctionTest.php | 4 +- .../Functions/DsnToContextFunctionTest.php | 2 +- pkg/enqueue/functions.php | 22 +- 46 files changed, 3347 insertions(+), 18 deletions(-) create mode 100644 docs/transport/amqp_bunny.md create mode 100644 pkg/amqp-bunny/.gitignore create mode 100644 pkg/amqp-bunny/.travis.yml create mode 100644 pkg/amqp-bunny/AmqpConnectionFactory.php create mode 100644 pkg/amqp-bunny/AmqpConsumer.php create mode 100644 pkg/amqp-bunny/AmqpContext.php create mode 100644 pkg/amqp-bunny/AmqpProducer.php create mode 100644 pkg/amqp-bunny/Buffer.php create mode 100644 pkg/amqp-bunny/LICENSE create mode 100644 pkg/amqp-bunny/README.md create mode 100644 pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php create mode 100644 pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php create mode 100644 pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php create mode 100644 pkg/amqp-bunny/Tests/AmqpConsumerTest.php create mode 100644 pkg/amqp-bunny/Tests/AmqpContextTest.php create mode 100644 pkg/amqp-bunny/Tests/AmqpProducerTest.php create mode 100644 pkg/amqp-bunny/Tests/BufferTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpConnectionFactoryTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpContextTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php create mode 100644 pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php create mode 100644 pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php create mode 100644 pkg/amqp-bunny/composer.json create mode 100644 pkg/amqp-bunny/phpunit.xml.dist delete mode 100644 pkg/amqp-ext/DeliveryMode.php create mode 100644 pkg/amqp-lib/README.md diff --git a/composer.json b/composer.json index 66573eaf8..cfb9fa72c 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "enqueue/stomp": "*@dev", "enqueue/amqp-ext": "*@dev", "enqueue/amqp-lib": "*@dev", + "enqueue/amqp-bunny": "*@dev", "php-amqplib/php-amqplib": "^2.7@dev", "enqueue/redis": "*@dev", "enqueue/fs": "*@dev", @@ -79,6 +80,10 @@ "type": "path", "url": "pkg/amqp-lib" }, + { + "type": "path", + "url": "pkg/amqp-bunny" + }, { "type": "path", "url": "pkg/redis" diff --git a/docs/index.md b/docs/index.md index e18f027aa..558f61206 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ * [Quick tour](quick_tour.md) * Transports - - Amqp based on [the ext](docs/transport/amqp.md), [the lib](docs/transport/amqp_lib.md) + - Amqp based on [the ext](docs/transport/amqp.md), [bunny](docs/transport/amqp_bunny.md), [the lib](docs/transport/amqp_lib.md) - [Amazon SQS](transport/sqs.md) - [Beanstalk (Pheanstalk)](transport/pheanstalk.md) - [Gearman](transport/gearman.md) diff --git a/docs/transport/amqp_bunny.md b/docs/transport/amqp_bunny.md new file mode 100644 index 000000000..69afaad76 --- /dev/null +++ b/docs/transport/amqp_bunny.md @@ -0,0 +1,195 @@ +# AMQP transport + +Implements [AMQP specifications](https://www.rabbitmq.com/specification.html) and implements [amqp interop](https://github.com/queue-interop/amqp-interop) interfaces. +Build on top of [bunny lib](https://github.com/jakubkulhan/bunny). + +* [Installation](#installation) +* [Create context](#create-context) +* [Declare topic](#declare-topic) +* [Declare queue](#decalre-queue) +* [Bind queue to topic](#bind-queue-to-topic) +* [Send message to topic](#send-message-to-topic) +* [Send message to queue](#send-message-to-queue) +* [Send priority message](#send-priority-message) +* [Send expiration message](#send-expiration-message) +* [Consume message](#consume-message) +* [Purge queue messages](#purge-queue-messages) + +## Installation + +```bash +$ composer require enqueue/amqp-bunny +``` + +## Create context + +```php + 'example.com', + 'port' => 1000, + 'vhost' => '/', + 'user' => 'user', + 'pass' => 'pass', + 'persisted' => false, +]); + +// same as above but given as DSN string +$connectionFactory = new AmqpConnectionFactory('amqp://user:pass@example.com:10000/%2f'); + +$psrContext = $connectionFactory->createContext(); +``` + +## Declare topic. + +Declare topic operation creates a topic on a broker side. + +```php +createTopic('foo'); +$fooTopic->setType(AmqpTopic::TYPE_FANOUT); +$psrContext->declareTopic($fooTopic); + +// to remove topic use delete topic method +//$psrContext->deleteTopic($fooTopic); +``` + +## Declare queue. + +Declare queue operation creates a queue on a broker side. + +```php +createQueue('foo'); +$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE); +$psrContext->declareQueue($fooQueue); + +// to remove topic use delete queue method +//$psrContext->deleteQueue($fooQueue); +``` + +## Bind queue to topic + +Connects a queue to the topic. So messages from that topic comes to the queue and could be processed. + +```php +bind(new AmqpBind($fooTopic, $fooQueue)); +``` + +## Send message to topic + +```php +createMessage('Hello world!'); + +$psrContext->createProducer()->send($fooTopic, $message); +``` + +## Send message to queue + +```php +createMessage('Hello world!'); + +$psrContext->createProducer()->send($fooQueue, $message); +``` + +## Send priority message + +```php +createQueue('foo'); +$fooQueue->addFlag(AmqpQueue::FLAG_DURABLE); +$fooQueue->setArguments(['x-max-priority' => 10]); +$psrContext->declareQueue($fooQueue); + +$message = $psrContext->createMessage('Hello world!'); + +$psrContext->createProducer() + ->setPriority(5) // the higher priority the sooner a message gets to a consumer + // + ->send($fooQueue, $message) +; +``` + +## Send expiration message + +```php +createMessage('Hello world!'); + +$psrContext->createProducer() + ->setTimeToLive(60000) // 60 sec + // + ->send($fooQueue, $message) +; +``` + +## Consume message: + +```php +createConsumer($fooQueue); + +$message = $consumer->receive(); + +// process a message + +$consumer->acknowledge($message); +// $consumer->reject($message); +``` + +## Purge queue messages: + +```php +createQueue('aQueue'); + +$psrContext->purgeQueue($queue); +``` + +[back to index](../index.md) \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 8ea7f3d2b..451898eb0 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -25,6 +25,10 @@ pkg/amqp-ext/Tests + + pkg/amqp-bunny/Tests + + pkg/fs/Tests diff --git a/pkg/amqp-bunny/.gitignore b/pkg/amqp-bunny/.gitignore new file mode 100644 index 000000000..a770439e5 --- /dev/null +++ b/pkg/amqp-bunny/.gitignore @@ -0,0 +1,6 @@ +*~ +/composer.lock +/composer.phar +/phpunit.xml +/vendor/ +/.idea/ diff --git a/pkg/amqp-bunny/.travis.yml b/pkg/amqp-bunny/.travis.yml new file mode 100644 index 000000000..a3f4ced92 --- /dev/null +++ b/pkg/amqp-bunny/.travis.yml @@ -0,0 +1,21 @@ +sudo: false + +git: + depth: 1 + +language: php + +php: + - '5.6' + - '7.0' + +cache: + directories: + - $HOME/.composer/cache + +install: + - composer self-update + - composer install + +script: + - vendor/bin/phpunit --exclude-group=functional diff --git a/pkg/amqp-bunny/AmqpConnectionFactory.php b/pkg/amqp-bunny/AmqpConnectionFactory.php new file mode 100644 index 000000000..cb73b8ae4 --- /dev/null +++ b/pkg/amqp-bunny/AmqpConnectionFactory.php @@ -0,0 +1,159 @@ + '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.', + * ] + * + * or + * + * amqp://user:pass@host:10000/vhost?lazy=true&socket=true + * + * @param array|string $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'); + } + + $this->config = array_replace($this->defaultConfig(), $config); + + $supportedMethods = ['basic_get', 'basic_consume']; + if (false == in_array($this->config['receive_method'], $supportedMethods, true)) { + throw new \LogicException(sprintf( + 'Invalid "receive_method" option value "%s". It could be only "%s"', + $this->config['receive_method'], + implode('", "', $supportedMethods) + )); + } + } + + /** + * @return AmqpContext + */ + public function createContext() + { + if ($this->config['lazy']) { + return new AmqpContext(function () { + return $this->establishConnection()->channel(); + }, $this->config); + } + + return new AmqpContext($this->establishConnection()->channel(), $this->config); + } + + /** + * @return Client + */ + private function establishConnection() + { + if (false == $this->client) { + $this->client = new Client($this->config); + $this->client->connect(); + } + + return $this->client; + } + + /** + * @param string $dsn + * + * @return array + */ + private function parseDsn($dsn) + { + $dsnConfig = parse_url(https://github.com/$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']); + + $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, + ]; + } +} diff --git a/pkg/amqp-bunny/AmqpConsumer.php b/pkg/amqp-bunny/AmqpConsumer.php new file mode 100644 index 000000000..1b59f31e8 --- /dev/null +++ b/pkg/amqp-bunny/AmqpConsumer.php @@ -0,0 +1,299 @@ +channel = $channel; + $this->queue = $queue; + $this->buffer = $buffer; + $this->receiveMethod = $receiveMethod; + $this->flags = self::FLAG_NOPARAM; + + $this->isInit = false; + } + + /** + * {@inheritdoc} + */ + public function setConsumerTag($consumerTag) + { + if ($this->isInit) { + throw new Exception('Consumer tag is not mutable after it has been subscribed to broker'); + } + + $this->consumerTag = $consumerTag; + } + + /** + * {@inheritdoc} + */ + public function getConsumerTag() + { + return $this->consumerTag; + } + + /** + * {@inheritdoc} + */ + public function clearFlags() + { + $this->flags = self::FLAG_NOPARAM; + } + + /** + * {@inheritdoc} + */ + public function addFlag($flag) + { + $this->flags |= $flag; + } + + /** + * {@inheritdoc} + */ + public function getFlags() + { + return $this->flags; + } + + /** + * {@inheritdoc} + */ + public function setFlags($flags) + { + $this->flags = $flags; + } + + /** + * {@inheritdoc} + */ + public function getQueue() + { + return $this->queue; + } + + /** + * {@inheritdoc} + */ + public function receive($timeout = 0) + { + if ('basic_get' == $this->receiveMethod) { + return $this->receiveBasicGet($timeout); + } + + if ('basic_consume' == $this->receiveMethod) { + return $this->receiveBasicConsume($timeout); + } + + throw new \LogicException('The "receiveMethod" is not supported'); + } + + /** + * {@inheritdoc} + */ + public function receiveNoWait() + { + if ($message = $this->channel->get($this->queue->getQueueName(), (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK))) { + $this->bunnyMessages[$message->deliveryTag] = $message; + + return $this->convertMessage($message); + } + } + + /** + * @param InteropAmqpMessage $message + */ + public function acknowledge(PsrMessage $message) + { + InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); + + if (isset($this->bunnyMessages[$message->getDeliveryTag()])) { + $this->channel->ack($this->bunnyMessages[$message->getDeliveryTag()]); + + unset($this->bunnyMessages[$message->getDeliveryTag()]); + } + } + + /** + * @param InteropAmqpMessage $message + * @param bool $requeue + */ + public function reject(PsrMessage $message, $requeue = false) + { + InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); + + if (isset($this->bunnyMessages[$message->getDeliveryTag()])) { + $this->channel->reject($this->bunnyMessages[$message->getDeliveryTag()], $requeue); + + unset($this->bunnyMessages[$message->getDeliveryTag()]); + } + } + + /** + * @param Message $bunnyMessage + * + * @return InteropAmqpMessage + */ + private function convertMessage(Message $bunnyMessage) + { + $headers = $bunnyMessage->headers; + + $properties = []; + if (isset($headers['application_headers'])) { + $properties = $headers['application_headers']; + } + unset($headers['application_headers']); + + $message = new AmqpMessage($bunnyMessage->content, $properties, $headers); + $message->setDeliveryTag($bunnyMessage->deliveryTag); + $message->setRedelivered($bunnyMessage->redelivered); + $message->setRoutingKey($bunnyMessage->routingKey); + + return $message; + } + + /** + * @param int $timeout + * + * @return InteropAmqpMessage|null + */ + private function receiveBasicGet($timeout) + { + $end = microtime(true) + ($timeout / 1000); + + while (0 === $timeout || microtime(true) < $end) { + if ($message = $this->receiveNoWait()) { + return $message; + } + + usleep(100000); //100ms + } + } + + /** + * @param int $timeout + * + * @return InteropAmqpMessage|null + */ + private function receiveBasicConsume($timeout) + { + if (false === $this->isInit) { + $callback = function (Message $message, Channel $channel, Client $bunny) { + $receivedMessage = $this->convertMessage($message); + $receivedMessage->setConsumerTag($message->consumerTag); + + $this->bunnyMessages[$message->deliveryTag] = $message; + $this->buffer->push($receivedMessage->getConsumerTag(), $receivedMessage); + + $bunny->stop(); + }; + + $frame = $this->channel->consume( + $callback, + $this->queue->getQueueName(), + $this->getConsumerTag() ?: $this->getQueue()->getConsumerTag(), + (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOLOCAL), + (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOACK), + (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_EXCLUSIVE), + (bool) ($this->getFlags() & InteropAmqpConsumer::FLAG_NOWAIT) + ); + + $this->consumerTag = $frame->consumerTag; + + if (empty($this->consumerTag)) { + throw new Exception('Got empty consumer tag'); + } + + $this->isInit = true; + } + + if ($message = $this->buffer->pop($this->consumerTag)) { + return $message; + } + + while (true) { + $start = microtime(true); + + $this->channel->getClient()->run($timeout / 1000); + + if ($message = $this->buffer->pop($this->consumerTag)) { + return $message; + } + + // is here when consumed message is not for this consumer + + // as timeout is infinite have to continue consumption, but it can overflow message buffer + if ($timeout <= 0) { + continue; + } + + // compute remaining timeout and continue until time is up + $stop = microtime(true); + $timeout -= ($stop - $start) * 1000; + + if ($timeout <= 0) { + break; + } + } + } +} diff --git a/pkg/amqp-bunny/AmqpContext.php b/pkg/amqp-bunny/AmqpContext.php new file mode 100644 index 000000000..7a596dd61 --- /dev/null +++ b/pkg/amqp-bunny/AmqpContext.php @@ -0,0 +1,324 @@ +config = array_replace([ + 'receive_method' => 'basic_get', + 'qos_prefetch_size' => 0, + 'qos_prefetch_count' => 1, + 'qos_global' => false, + ], $config); + + if ($bunnyChannel instanceof Channel) { + $this->bunnyChannel = $bunnyChannel; + } elseif (is_callable($bunnyChannel)) { + $this->bunnyChannelFactory = $bunnyChannel; + } else { + throw new \InvalidArgumentException('The bunnyChannel argument must be either \Bunny\Channel or callable that return it.'); + } + + $this->buffer = new Buffer(); + } + + /** + * @param string|null $body + * @param array $properties + * @param array $headers + * + * @return InteropAmqpMessage + */ + public function createMessage($body = '', array $properties = [], array $headers = []) + { + return new AmqpMessage($body, $properties, $headers); + } + + /** + * @param string $name + * + * @return InteropAmqpQueue + */ + public function createQueue($name) + { + return new AmqpQueue($name); + } + + /** + * @param string $name + * + * @return InteropAmqpTopic + */ + public function createTopic($name) + { + return new AmqpTopic($name); + } + + /** + * @param PsrDestination $destination + * + * @return AmqpConsumer + */ + public function createConsumer(PsrDestination $destination) + { + $destination instanceof PsrTopic + ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class) + : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class) + ; + + if ($destination instanceof AmqpTopic) { + $queue = $this->createTemporaryQueue(); + $this->bind(new AmqpBind($destination, $queue, $queue->getQueueName())); + + return new AmqpConsumer($this->getBunnyChannel(), $queue, $this->buffer, $this->config['receive_method']); + } + + return new AmqpConsumer($this->getBunnyChannel(), $destination, $this->buffer, $this->config['receive_method']); + } + + /** + * @return AmqpProducer + */ + public function createProducer() + { + return new AmqpProducer($this->getBunnyChannel()); + } + + /** + * @return InteropAmqpQueue + */ + public function createTemporaryQueue() + { + $frame = $this->getBunnyChannel()->queueDeclare('', false, false, true, false); + + $queue = $this->createQueue($frame->queue); + $queue->addFlag(InteropAmqpQueue::FLAG_EXCLUSIVE); + + return $queue; + } + + /** + * {@inheritdoc} + */ + public function declareTopic(InteropAmqpTopic $topic) + { + $this->getBunnyChannel()->exchangeDeclare( + $topic->getTopicName(), + $topic->getType(), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_PASSIVE), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_DURABLE), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_AUTODELETE), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_INTERNAL), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT), + $topic->getArguments() + ); + } + + /** + * {@inheritdoc} + */ + public function deleteTopic(InteropAmqpTopic $topic) + { + $this->getBunnyChannel()->exchangeDelete( + $topic->getTopicName(), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_IFUNUSED), + (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT) + ); + } + + /** + * {@inheritdoc} + */ + public function declareQueue(InteropAmqpQueue $queue) + { + $frame = $this->getBunnyChannel()->queueDeclare( + $queue->getQueueName(), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_PASSIVE), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_DURABLE), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_EXCLUSIVE), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_AUTODELETE), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT), + $queue->getArguments() + ); + + return $frame->messageCount; + } + + /** + * {@inheritdoc} + */ + public function deleteQueue(InteropAmqpQueue $queue) + { + $this->getBunnyChannel()->queueDelete( + $queue->getQueueName(), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_IFUNUSED), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_IFEMPTY), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT) + ); + } + + /** + * {@inheritdoc} + */ + public function purgeQueue(InteropAmqpQueue $queue) + { + $this->getBunnyChannel()->queuePurge( + $queue->getQueueName(), + (bool) ($queue->getFlags() & InteropAmqpQueue::FLAG_NOWAIT) + ); + } + + /** + * {@inheritdoc} + */ + public function bind(InteropAmqpBind $bind) + { + if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { + throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic'); + } + + // bind exchange to exchange + if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { + $this->getBunnyChannel()->exchangeBind( + $bind->getTarget()->getTopicName(), + $bind->getSource()->getTopicName(), + $bind->getRoutingKey(), + (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + $bind->getArguments() + ); + // bind queue to exchange + } elseif ($bind->getSource() instanceof InteropAmqpQueue) { + $this->getBunnyChannel()->queueBind( + $bind->getSource()->getQueueName(), + $bind->getTarget()->getTopicName(), + $bind->getRoutingKey(), + (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + $bind->getArguments() + ); + // bind exchange to queue + } else { + $this->getBunnyChannel()->queueBind( + $bind->getTarget()->getQueueName(), + $bind->getSource()->getTopicName(), + $bind->getRoutingKey(), + (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + $bind->getArguments() + ); + } + } + + /** + * {@inheritdoc} + */ + public function unbind(InteropAmqpBind $bind) + { + if ($bind->getSource() instanceof InteropAmqpQueue && $bind->getTarget() instanceof InteropAmqpQueue) { + throw new Exception('Is not possible to bind queue to queue. It is possible to bind topic to queue or topic to topic'); + } + + // bind exchange to exchange + if ($bind->getSource() instanceof InteropAmqpTopic && $bind->getTarget() instanceof InteropAmqpTopic) { + $this->getBunnyChannel()->exchangeUnbind( + $bind->getTarget()->getTopicName(), + $bind->getSource()->getTopicName(), + $bind->getRoutingKey(), + (bool) ($bind->getFlags() & InteropAmqpBind::FLAG_NOWAIT), + $bind->getArguments() + ); + // bind queue to exchange + } elseif ($bind->getSource() instanceof InteropAmqpQueue) { + $this->getBunnyChannel()->queueUnbind( + $bind->getSource()->getQueueName(), + $bind->getTarget()->getTopicName(), + $bind->getRoutingKey(), + $bind->getArguments() + ); + // bind exchange to queue + } else { + $this->getBunnyChannel()->queueUnbind( + $bind->getTarget()->getQueueName(), + $bind->getSource()->getTopicName(), + $bind->getRoutingKey(), + $bind->getArguments() + ); + } + } + + public function close() + { + if ($this->bunnyChannel) { + $this->bunnyChannel->close(); + } + } + + /** + * {@inheritdoc} + */ + public function setQos($prefetchSize, $prefetchCount, $global) + { + $this->getBunnyChannel()->qos($prefetchSize, $prefetchCount, $global); + } + + /** + * @return Channel + */ + public function getBunnyChannel() + { + if (false == $this->bunnyChannel) { + $bunnyChannel = call_user_func($this->bunnyChannelFactory); + if (false == $bunnyChannel instanceof Channel) { + throw new \LogicException(sprintf( + 'The factory must return instance of \Bunny\Channel. It returned %s', + is_object($bunnyChannel) ? get_class($bunnyChannel) : gettype($bunnyChannel) + )); + } + + $this->bunnyChannel = $bunnyChannel; + } + + return $this->bunnyChannel; + } +} diff --git a/pkg/amqp-bunny/AmqpProducer.php b/pkg/amqp-bunny/AmqpProducer.php new file mode 100644 index 000000000..9a19cd970 --- /dev/null +++ b/pkg/amqp-bunny/AmqpProducer.php @@ -0,0 +1,141 @@ +channel = $channel; + } + + /** + * @param InteropAmqpTopic|InteropAmqpQueue $destination + * @param InteropAmqpMessage $message + */ + public function send(PsrDestination $destination, PsrMessage $message) + { + $destination instanceof PsrTopic + ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class) + : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class) + ; + + InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); + + if (null !== $this->priority && null === $message->getPriority()) { + $message->setPriority($this->priority); + } + + if (null !== $this->timeToLive && null === $message->getExpiration()) { + $message->setExpiration($this->timeToLive); + } + + $amqpProperties = $message->getHeaders(); + + if ($appProperties = $message->getProperties()) { + $amqpProperties['application_headers'] = $appProperties; + } + + if ($destination instanceof InteropAmqpTopic) { + $this->channel->publish( + $message->getBody(), + $amqpProperties, + $destination->getTopicName(), + $message->getRoutingKey(), + (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY), + (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE) + ); + } else { + $this->channel->publish( + $message->getBody(), + $amqpProperties, + '', + $destination->getQueueName(), + (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_MANDATORY), + (bool) ($message->getFlags() & InteropAmqpMessage::FLAG_IMMEDIATE) + ); + } + } + + /** + * {@inheritdoc} + */ + public function setDeliveryDelay($deliveryDelay) + { + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); + } + + /** + * {@inheritdoc} + */ + public function getDeliveryDelay() + { + return null; + } + + /** + * {@inheritdoc} + */ + public function setPriority($priority) + { + $this->priority = $priority; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getPriority() + { + return $this->priority; + } + + /** + * {@inheritdoc} + */ + public function setTimeToLive($timeToLive) + { + $this->timeToLive = $timeToLive; + + return $this; + } + + /** + * {@inheritdoc} + */ + public function getTimeToLive() + { + return $this->timeToLive; + } +} diff --git a/pkg/amqp-bunny/Buffer.php b/pkg/amqp-bunny/Buffer.php new file mode 100644 index 000000000..1912274f7 --- /dev/null +++ b/pkg/amqp-bunny/Buffer.php @@ -0,0 +1,43 @@ + [AmqpMessage, AmqpMessage ...]] + */ + private $messages; + + public function __construct() + { + $this->messages = []; + } + + /** + * @param string $consumerTag + * @param AmqpMessage $message + */ + public function push($consumerTag, AmqpMessage $message) + { + if (false == array_key_exists($consumerTag, $this->messages)) { + $this->messages[$consumerTag] = []; + } + + $this->messages[$consumerTag][] = $message; + } + + /** + * @param string $consumerTag + * + * @return AmqpMessage|null + */ + public function pop($consumerTag) + { + if (false == empty($this->messages[$consumerTag])) { + return array_shift($this->messages[$consumerTag]); + } + } +} diff --git a/pkg/amqp-bunny/LICENSE b/pkg/amqp-bunny/LICENSE new file mode 100644 index 000000000..d9736f8bf --- /dev/null +++ b/pkg/amqp-bunny/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright (c) 2017 Kotliar Maksym + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/pkg/amqp-bunny/README.md b/pkg/amqp-bunny/README.md new file mode 100644 index 000000000..5d600f97d --- /dev/null +++ b/pkg/amqp-bunny/README.md @@ -0,0 +1,26 @@ +# AMQP Transport + +[![Gitter](https://badges.gitter.im/php-enqueue/Lobby.svg)](https://gitter.im/php-enqueue/Lobby) +[![Build Status](https://travis-ci.org/php-enqueue/amqp-bunny.png?branch=master)](https://travis-ci.org/php-enqueue/amqp-bunny) +[![Total Downloads](https://poser.pugx.org/enqueue/amqp-bunny/d/total.png)](https://packagist.org/packages/enqueue/amqp-bunny) +[![Latest Stable Version](https://poser.pugx.org/enqueue/amqp-bunny/version.png)](https://packagist.org/packages/enqueue/amqp-bunny) + +This is an implementation of [amqp interop](https://github.com/queue-interop/amqp-interop). It uses [bunny](https://github.com/jakubkulhan/bunny) internally. + +## Resources + +* [Documentation](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md) +* [Questions](https://gitter.im/php-enqueue/Lobby) +* [Issue Tracker](https://github.com/php-enqueue/enqueue-dev/issues) + +## Developed by Forma-Pro + +Forma-Pro is a full stack development company which interests also spread to open source development. +Being a team of strong professionals we have an aim an ability to help community by developing cutting edge solutions in the areas of e-commerce, docker & microservice oriented architecture where we have accumulated a huge many-years experience. +Our main specialization is Symfony framework based solution, but we are always looking to the technologies that allow us to do our job the best way. We are committed to creating solutions that revolutionize the way how things are developed in aspects of architecture & scalability. + +If you have any questions and inquires about our open source development, this product particularly or any other matter feel free to contact at opensource@forma-pro.com + +## License + +It is released under the [MIT License](LICENSE). \ No newline at end of file diff --git a/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php b/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php new file mode 100644 index 000000000..f83202839 --- /dev/null +++ b/pkg/amqp-bunny/Symfony/AmqpBunnyTransportFactory.php @@ -0,0 +1,140 @@ +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 new file mode 100644 index 000000000..20de33382 --- /dev/null +++ b/pkg/amqp-bunny/Symfony/RabbitMqAmqpBunnyTransportFactory.php @@ -0,0 +1,53 @@ +children() + ->booleanNode('delay_plugin_installed') + ->defaultFalse() + ->info('The option tells whether RabbitMQ broker has delay plugin installed or not') + ->end() + ; + } + + /** + * {@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/AmqpConnectionFactoryConfigTest.php b/pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php new file mode 100644 index 000000000..e659cef68 --- /dev/null +++ b/pkg/amqp-bunny/Tests/AmqpConnectionFactoryConfigTest.php @@ -0,0 +1,235 @@ +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://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/AmqpConsumerTest.php b/pkg/amqp-bunny/Tests/AmqpConsumerTest.php new file mode 100644 index 000000000..bc716174a --- /dev/null +++ b/pkg/amqp-bunny/Tests/AmqpConsumerTest.php @@ -0,0 +1,242 @@ +assertClassImplements(PsrConsumer::class, AmqpConsumer::class); + } + + public function testCouldBeConstructedWithContextAndQueueAndBufferAsArguments() + { + new AmqpConsumer( + $this->createChannelMock(), + new AmqpQueue('aName'), + new Buffer(), + 'basic_get' + ); + } + + public function testShouldReturnQueue() + { + $queue = new AmqpQueue('aName'); + + $consumer = new AmqpConsumer($this->createChannelMock(), $queue, new Buffer(), 'basic_get'); + + $this->assertSame($queue, $consumer->getQueue()); + } + + public function testOnAcknowledgeShouldThrowExceptionIfNotAmqpMessage() + { + $consumer = new AmqpConsumer($this->createChannelMock(), new AmqpQueue('aName'), new Buffer(), 'basic_get'); + + $this->expectException(InvalidMessageException::class); + $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but'); + + $consumer->acknowledge(new NullMessage()); + } + + public function testOnRejectShouldThrowExceptionIfNotAmqpMessage() + { + $consumer = new AmqpConsumer($this->createChannelMock(), new AmqpQueue('aName'), new Buffer(), 'basic_get'); + + $this->expectException(InvalidMessageException::class); + $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but'); + + $consumer->reject(new NullMessage()); + } + + public function testOnAcknowledgeShouldAcknowledgeMessage() + { + $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('get') + ->willReturn($bunnyMessage) + ; + $channel + ->expects($this->once()) + ->method('ack') + ->with($this->identicalTo($bunnyMessage)) + ; + + $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get'); + + $message = $consumer->receiveNoWait(); + + // guard + $this->assertSame('delivery-tag', $message->getDeliveryTag()); + + $consumer->acknowledge($message); + } + + public function testOnRejectShouldRejectMessage() + { + $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('get') + ->willReturn($bunnyMessage) + ; + $channel + ->expects($this->once()) + ->method('reject') + ->with($this->identicalTo($bunnyMessage), $this->isFalse()) + ; + + $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get'); + + $message = $consumer->receiveNoWait(); + + // guard + $this->assertSame('delivery-tag', $message->getDeliveryTag()); + + $consumer->reject($message, false); + } + + public function testOnRejectShouldRequeueMessage() + { + $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('get') + ->willReturn($bunnyMessage) + ; + $channel + ->expects($this->once()) + ->method('reject') + ->with($this->identicalTo($bunnyMessage), $this->isTrue()) + ; + + $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get'); + + $message = $consumer->receiveNoWait(); + + // guard + $this->assertSame('delivery-tag', $message->getDeliveryTag()); + + $consumer->reject($message, true); + } + + public function testShouldReturnMessageOnReceiveNoWait() + { + $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('get') + ->willReturn($bunnyMessage) + ; + + $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get'); + + $message = new AmqpMessage(); + $message->setDeliveryTag('delivery-tag'); + + $message = $consumer->receiveNoWait(); + + $this->assertInstanceOf(AmqpMessage::class, $message); + $this->assertSame('body', $message->getBody()); + $this->assertSame('delivery-tag', $message->getDeliveryTag()); + $this->assertTrue($message->isRedelivered()); + } + + public function testShouldReturnMessageOnReceiveWithReceiveMethodBasicGet() + { + $bunnyMessage = new Message('', 'delivery-tag', true, '', '', [], 'body'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('get') + ->willReturn($bunnyMessage) + ; + + $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_get'); + + $message = new AmqpMessage(); + $message->setDeliveryTag('delivery-tag'); + + $message = $consumer->receive(); + + $this->assertInstanceOf(AmqpMessage::class, $message); + $this->assertSame('body', $message->getBody()); + $this->assertSame('delivery-tag', $message->getDeliveryTag()); + $this->assertTrue($message->isRedelivered()); + } + + public function testShouldCallExpectedMethodsWhenReceiveWithBasicConsumeMethod() + { + $frame = new MethodBasicConsumeOkFrame(); + $frame->consumerTag = 'theConsumerTag'; + + $client = $this->createClientMock(); + $client + ->expects($this->atLeastOnce()) + ->method('run') + ; + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('consume') + ->willReturn($frame) + ; + $channel + ->expects($this->atLeastOnce()) + ->method('getClient') + ->willReturn($client) + ; + + $consumer = new AmqpConsumer($channel, new AmqpQueue('aName'), new Buffer(), 'basic_consume'); + + $message = new AmqpMessage(); + $message->setDeliveryTag('delivery-tag'); + $consumer->receive(1234); + + $this->assertSame('theConsumerTag', $consumer->getConsumerTag()); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|Client + */ + public function createClientMock() + { + return $this->createMock(Client::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|Channel + */ + public function createChannelMock() + { + return $this->createMock(Channel::class); + } +} diff --git a/pkg/amqp-bunny/Tests/AmqpContextTest.php b/pkg/amqp-bunny/Tests/AmqpContextTest.php new file mode 100644 index 000000000..74f435ea5 --- /dev/null +++ b/pkg/amqp-bunny/Tests/AmqpContextTest.php @@ -0,0 +1,245 @@ +createChannelMock(); + $channel + ->expects($this->once()) + ->method('exchangeDeclare') + ->with( + $this->identicalTo('name'), + $this->identicalTo('type'), + $this->isTrue(), + $this->isTrue(), + $this->isTrue(), + $this->isTrue(), + $this->isTrue(), + $this->identicalTo(['key' => 'value']) + ) + ; + + $topic = new AmqpTopic('name'); + $topic->setType('type'); + $topic->setArguments(['key' => 'value']); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); + $topic->addFlag(AmqpTopic::FLAG_NOWAIT); + $topic->addFlag(AmqpTopic::FLAG_PASSIVE); + $topic->addFlag(AmqpTopic::FLAG_INTERNAL); + $topic->addFlag(AmqpTopic::FLAG_AUTODELETE); + + $session = new AmqpContext($channel); + $session->declareTopic($topic); + } + + public function testShouldDeleteTopic() + { + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('exchangeDelete') + ->with( + $this->identicalTo('name'), + $this->isTrue(), + $this->isTrue() + ) + ; + + $topic = new AmqpTopic('name'); + $topic->setType('type'); + $topic->setArguments(['key' => 'value']); + $topic->addFlag(AmqpTopic::FLAG_IFUNUSED); + $topic->addFlag(AmqpTopic::FLAG_NOWAIT); + + $session = new AmqpContext($channel); + $session->deleteTopic($topic); + } + + public function testShouldDeclareQueue() + { + $frame = new MethodQueueDeclareOkFrame(); + $frame->queue = 'name'; + $frame->messageCount = 123; + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('queueDeclare') + ->with( + $this->identicalTo('name'), + $this->isTrue(), + $this->isTrue(), + $this->isTrue(), + $this->isTrue(), + $this->isTrue(), + $this->identicalTo(['key' => 'value']) + ) + ->willReturn($frame) + ; + + $queue = new AmqpQueue('name'); + $queue->setArguments(['key' => 'value']); + $queue->addFlag(AmqpQueue::FLAG_AUTODELETE); + $queue->addFlag(AmqpQueue::FLAG_DURABLE); + $queue->addFlag(AmqpQueue::FLAG_NOWAIT); + $queue->addFlag(AmqpQueue::FLAG_PASSIVE); + $queue->addFlag(AmqpQueue::FLAG_EXCLUSIVE); + $queue->addFlag(AmqpQueue::FLAG_NOWAIT); + + $session = new AmqpContext($channel); + + $this->assertSame(123, $session->declareQueue($queue)); + } + + public function testShouldDeleteQueue() + { + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('queueDelete') + ->with( + $this->identicalTo('name'), + $this->isTrue(), + $this->isTrue(), + $this->isTrue() + ) + ; + + $queue = new AmqpQueue('name'); + $queue->setArguments(['key' => 'value']); + $queue->addFlag(AmqpQueue::FLAG_IFUNUSED); + $queue->addFlag(AmqpQueue::FLAG_IFEMPTY); + $queue->addFlag(AmqpQueue::FLAG_NOWAIT); + + $session = new AmqpContext($channel); + $session->deleteQueue($queue); + } + + public function testBindShouldBindTopicToTopic() + { + $source = new AmqpTopic('source'); + $target = new AmqpTopic('target'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('exchangeBind') + ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue()) + ; + + $context = new AmqpContext($channel); + $context->bind(new AmqpBind($target, $source, 'routing-key', 12345)); + } + + public function testBindShouldBindTopicToQueue() + { + $source = new AmqpTopic('source'); + $target = new AmqpQueue('target'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->exactly(2)) + ->method('queueBind') + ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue()) + ; + + $context = new AmqpContext($channel); + $context->bind(new AmqpBind($target, $source, 'routing-key', 12345)); + $context->bind(new AmqpBind($source, $target, 'routing-key', 12345)); + } + + public function testShouldUnBindTopicFromTopic() + { + $source = new AmqpTopic('source'); + $target = new AmqpTopic('target'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('exchangeUnbind') + ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), $this->isTrue()) + ; + + $context = new AmqpContext($channel); + $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345)); + } + + public function testShouldUnBindTopicFromQueue() + { + $source = new AmqpTopic('source'); + $target = new AmqpQueue('target'); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->exactly(2)) + ->method('queueUnbind') + ->with($this->identicalTo('target'), $this->identicalTo('source'), $this->identicalTo('routing-key'), ['key' => 'value']) + ; + + $context = new AmqpContext($channel); + $context->unbind(new AmqpBind($target, $source, 'routing-key', 12345, ['key' => 'value'])); + $context->unbind(new AmqpBind($source, $target, 'routing-key', 12345, ['key' => 'value'])); + } + + public function testShouldCloseChannelConnection() + { + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('close') + ; + + $context = new AmqpContext($channel); + $context->createProducer(); + + $context->close(); + } + + public function testShouldPurgeQueue() + { + $queue = new AmqpQueue('queue'); + $queue->addFlag(AmqpQueue::FLAG_NOWAIT); + + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('queuePurge') + ->with($this->identicalTo('queue'), $this->isTrue()) + ; + + $context = new AmqpContext($channel); + $context->purgeQueue($queue); + } + + public function testShouldSetQos() + { + $channel = $this->createChannelMock(); + $channel + ->expects($this->once()) + ->method('qos') + ->with($this->identicalTo(123), $this->identicalTo(456), $this->isTrue()) + ; + + $context = new AmqpContext($channel); + $context->setQos(123, 456, true); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|Channel + */ + public function createChannelMock() + { + return $this->createMock(Channel::class); + } +} diff --git a/pkg/amqp-bunny/Tests/AmqpProducerTest.php b/pkg/amqp-bunny/Tests/AmqpProducerTest.php new file mode 100644 index 000000000..91a029684 --- /dev/null +++ b/pkg/amqp-bunny/Tests/AmqpProducerTest.php @@ -0,0 +1,153 @@ +createBunnyChannelMock()); + } + + public function testShouldImplementPsrProducerInterface() + { + $this->assertClassImplements(PsrProducer::class, AmqpProducer::class); + } + + public function testShouldThrowExceptionWhenDestinationTypeIsInvalid() + { + $producer = new AmqpProducer($this->createBunnyChannelMock()); + + $this->expectException(InvalidDestinationException::class); + $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpQueue but got'); + + $producer->send($this->createDestinationMock(), new AmqpMessage()); + } + + public function testShouldThrowExceptionWhenMessageTypeIsInvalid() + { + $producer = new AmqpProducer($this->createBunnyChannelMock()); + + $this->expectException(InvalidMessageException::class); + $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but it is'); + + $producer->send(new AmqpTopic('name'), $this->createMessageMock()); + } + + public function testShouldPublishMessageToTopic() + { + $channel = $this->createBunnyChannelMock(); + $channel + ->expects($this->once()) + ->method('publish') + ->with('body', [], 'topic', 'routing-key', false, false) + ; + + $topic = new AmqpTopic('topic'); + + $message = new AmqpMessage('body'); + $message->setRoutingKey('routing-key'); + + $producer = new AmqpProducer($channel); + $producer->send($topic, $message); + } + + public function testShouldPublishMessageToQueue() + { + $channel = $this->createBunnyChannelMock(); + $channel + ->expects($this->once()) + ->method('publish') + ->with('body', [], '', 'queue', false, false) + ; + + $queue = new AmqpQueue('queue'); + + $producer = new AmqpProducer($channel); + $producer->send($queue, new AmqpMessage('body')); + } + + public function testShouldSetMessageHeaders() + { + $channel = $this->createBunnyChannelMock(); + $channel + ->expects($this->once()) + ->method('publish') + ->with($this->anything(), ['content_type' => 'text/plain']) + ; + + $producer = new AmqpProducer($channel); + $producer->send(new AmqpTopic('name'), new AmqpMessage('body', [], ['content_type' => 'text/plain'])); + } + + public function testShouldSetMessageProperties() + { + $channel = $this->createBunnyChannelMock(); + $channel + ->expects($this->once()) + ->method('publish') + ->with($this->anything(), ['application_headers' => ['key' => 'value']]) + ; + + $producer = new AmqpProducer($channel); + $producer->send(new AmqpTopic('name'), new AmqpMessage('body', ['key' => 'value'])); + } + + public function testShouldPropagateFlags() + { + $channel = $this->createBunnyChannelMock(); + $channel + ->expects($this->once()) + ->method('publish') + ->with($this->anything(), $this->anything(), $this->anything(), $this->anything(), true, true) + ; + + $message = new AmqpMessage('body'); + $message->addFlag(InteropAmqpMessage::FLAG_IMMEDIATE); + $message->addFlag(InteropAmqpMessage::FLAG_MANDATORY); + + $producer = new AmqpProducer($channel); + $producer->send(new AmqpTopic('name'), $message); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|PsrMessage + */ + private function createMessageMock() + { + return $this->createMock(PsrMessage::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|PsrDestination + */ + private function createDestinationMock() + { + return $this->createMock(PsrDestination::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|Channel + */ + private function createBunnyChannelMock() + { + return $this->createMock(Channel::class); + } +} diff --git a/pkg/amqp-bunny/Tests/BufferTest.php b/pkg/amqp-bunny/Tests/BufferTest.php new file mode 100644 index 000000000..6cb1ef0ad --- /dev/null +++ b/pkg/amqp-bunny/Tests/BufferTest.php @@ -0,0 +1,64 @@ +assertAttributeSame([], 'messages', $buffer); + } + + public function testShouldReturnNullIfNoMessagesInBuffer() + { + $buffer = new Buffer(); + + $this->assertNull($buffer->pop('aConsumerTag')); + $this->assertNull($buffer->pop('anotherConsumerTag')); + } + + public function testShouldPushMessageToBuffer() + { + $fooMessage = new AmqpMessage(); + $barMessage = new AmqpMessage(); + $bazMessage = new AmqpMessage(); + + $buffer = new Buffer(); + + $buffer->push('aConsumerTag', $fooMessage); + $buffer->push('aConsumerTag', $barMessage); + + $buffer->push('anotherConsumerTag', $bazMessage); + + $this->assertAttributeSame([ + 'aConsumerTag' => [$fooMessage, $barMessage], + 'anotherConsumerTag' => [$bazMessage], + ], 'messages', $buffer); + } + + public function testShouldPopMessageFromBuffer() + { + $fooMessage = new AmqpMessage(); + $barMessage = new AmqpMessage(); + + $buffer = new Buffer(); + + $buffer->push('aConsumerTag', $fooMessage); + $buffer->push('aConsumerTag', $barMessage); + + $this->assertSame($fooMessage, $buffer->pop('aConsumerTag')); + $this->assertSame($barMessage, $buffer->pop('aConsumerTag')); + $this->assertNull($buffer->pop('aConsumerTag')); + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpConnectionFactoryTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpConnectionFactoryTest.php new file mode 100644 index 000000000..d8d481527 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpConnectionFactoryTest.php @@ -0,0 +1,14 @@ +createMock(Channel::class); + + return new AmqpContext($channel); + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php new file mode 100644 index 000000000..c70f89079 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceivePriorityMessagesFromQueueTest.php @@ -0,0 +1,40 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $queue->setArguments(['x-max-priority' => 10]); + + $context->declareQueue($queue); + $context->purgeQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php new file mode 100644 index 000000000..5f5e07c0f --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveTimeToLiveMessagesFromQueueTest.php @@ -0,0 +1,38 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + $context->purgeQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php new file mode 100644 index 000000000..1111103c1 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromQueueTest.php @@ -0,0 +1,38 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + $context->purgeQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php new file mode 100644 index 000000000..4647239ef --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveFromTopicTest.php @@ -0,0 +1,40 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createTopic(PsrContext $context, $topicName) + { + $topic = $context->createTopic($topicName); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); + $context->declareTopic($topic); + + return $topic; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php new file mode 100644 index 000000000..461e98680 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromQueueTest.php @@ -0,0 +1,38 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + $context->purgeQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php new file mode 100644 index 000000000..8fa295b52 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToAndReceiveNoWaitFromTopicTest.php @@ -0,0 +1,40 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createTopic(PsrContext $context, $topicName) + { + $topic = $context->createTopic($topicName); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); + $context->declareTopic($topic); + + return $topic; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php new file mode 100644 index 000000000..49f502695 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicConsumeMethodTest.php @@ -0,0 +1,61 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queueName .= '_basic_consume'; + + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + $context->purgeQueue($queue); + + $context->bind(new AmqpBind($context->createTopic($queueName), $queue)); + + return $queue; + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createTopic(PsrContext $context, $topicName) + { + $topicName .= '_basic_consume'; + + $topic = $context->createTopic($topicName); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); + $context->declareTopic($topic); + + return $topic; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php new file mode 100644 index 000000000..c06dac310 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveFromQueueWithBasicGetMethodTest.php @@ -0,0 +1,57 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + $context->purgeQueue($queue); + + $context->bind(new AmqpBind($context->createTopic($queueName), $queue)); + + return $queue; + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createTopic(PsrContext $context, $topicName) + { + $topic = $context->createTopic($topicName); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); + $context->declareTopic($topic); + + return $topic; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php new file mode 100644 index 000000000..547c3b775 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendToTopicAndReceiveNoWaitFromQueueTest.php @@ -0,0 +1,57 @@ +createContext(); + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = $context->createQueue($queueName); + $context->declareQueue($queue); + $context->purgeQueue($queue); + + $context->bind(new AmqpBind($context->createTopic($queueName), $queue)); + + return $queue; + } + + /** + * {@inheritdoc} + * + * @param AmqpContext $context + */ + protected function createTopic(PsrContext $context, $topicName) + { + $topic = $context->createTopic($topicName); + $topic->setType(AmqpTopic::TYPE_FANOUT); + $topic->addFlag(AmqpTopic::FLAG_DURABLE); + $context->declareTopic($topic); + + return $topic; + } +} diff --git a/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php b/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php new file mode 100644 index 000000000..9b2a68bc2 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Symfony/AmqpBunnyTransportFactoryTest.php @@ -0,0 +1,218 @@ +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 new file mode 100644 index 000000000..4dd11871b --- /dev/null +++ b/pkg/amqp-bunny/Tests/Symfony/RabbitMqAmqpBunnyTransportFactoryTest.php @@ -0,0 +1,137 @@ +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_plugin_installed' => false, + '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_plugin_installed' => false, + ]); + + $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_plugin_installed' => false, + ]], $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_plugin_installed' => false, + ]); + + $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-bunny/composer.json b/pkg/amqp-bunny/composer.json new file mode 100644 index 000000000..130660212 --- /dev/null +++ b/pkg/amqp-bunny/composer.json @@ -0,0 +1,42 @@ +{ + "name": "enqueue/amqp-bunny", + "type": "library", + "description": "Message Queue Amqp Transport", + "keywords": ["messaging", "queue", "amqp", "bunny"], + "license": "MIT", + "repositories": [ + { + "type": "vcs", + "url": "git@github.com:php-enqueue/test.git" + } + ], + "require": { + "php": ">=5.6", + + "queue-interop/amqp-interop": "^0.6@dev", + "bunny/bunny": "^0.2.4", + "psr/log": "^1" + }, + "require-dev": { + "phpunit/phpunit": "~5.4.0", + "enqueue/test": "^0.7@dev", + "enqueue/enqueue": "^0.7@dev", + "enqueue/null": "^0.7@dev", + "queue-interop/queue-spec": "^0.5@dev" + }, + "autoload": { + "psr-4": { "Enqueue\\AmqpBunny\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "suggest": { + "enqueue/enqueue": "If you'd like to use advanced features like Client abstract layer or Symfony integration features" + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "0.7.x-dev" + } + } +} diff --git a/pkg/amqp-bunny/phpunit.xml.dist b/pkg/amqp-bunny/phpunit.xml.dist new file mode 100644 index 000000000..7d6c5ed3e --- /dev/null +++ b/pkg/amqp-bunny/phpunit.xml.dist @@ -0,0 +1,30 @@ + + + + + + + ./Tests + + + + + + . + + ./vendor + ./Tests + + + + diff --git a/pkg/amqp-ext/AmqpConnectionFactory.php b/pkg/amqp-ext/AmqpConnectionFactory.php index 537cb94c5..803038325 100644 --- a/pkg/amqp-ext/AmqpConnectionFactory.php +++ b/pkg/amqp-ext/AmqpConnectionFactory.php @@ -43,6 +43,10 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory */ 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)) { diff --git a/pkg/amqp-ext/DeliveryMode.php b/pkg/amqp-ext/DeliveryMode.php deleted file mode 100644 index 3dac593d6..000000000 --- a/pkg/amqp-ext/DeliveryMode.php +++ /dev/null @@ -1,9 +0,0 @@ - 'host', + 'port' => 10000, + 'vhost' => 'vhost', + 'user' => 'user', + 'pass' => 'pass', + 'read_timeout' => null, + 'write_timeout' => null, + 'connect_timeout' => null, + 'persisted' => false, + 'lazy' => true, + 'pre_fetch_count' => null, + 'pre_fetch_size' => null, + 'receive_method' => 'basic_get', + ], + ]; + yield [ 'amqp://user:pass@host:10000/vhost', [ diff --git a/pkg/amqp-lib/AmqpConnectionFactory.php b/pkg/amqp-lib/AmqpConnectionFactory.php index cbee87991..aad7b3ea3 100644 --- a/pkg/amqp-lib/AmqpConnectionFactory.php +++ b/pkg/amqp-lib/AmqpConnectionFactory.php @@ -46,6 +46,10 @@ class AmqpConnectionFactory implements InteropAmqpConnectionFactory */ 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)) { diff --git a/pkg/amqp-lib/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php index dcece273d..272ea8711 100644 --- a/pkg/amqp-lib/AmqpContext.php +++ b/pkg/amqp-lib/AmqpContext.php @@ -146,7 +146,7 @@ public function declareTopic(InteropAmqpTopic $topic) (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_AUTODELETE), (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_INTERNAL), (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT), - $topic->getArguments() + $topic->getArguments() ? new AMQPTable($topic->getArguments()) : null ); } diff --git a/pkg/amqp-lib/README.md b/pkg/amqp-lib/README.md new file mode 100644 index 000000000..9d92954a3 --- /dev/null +++ b/pkg/amqp-lib/README.md @@ -0,0 +1,26 @@ +# AMQP Transport + +[![Gitter](https://badges.gitter.im/php-enqueue/Lobby.svg)](https://gitter.im/php-enqueue/Lobby) +[![Build Status](https://travis-ci.org/php-enqueue/amqp-lib.png?branch=master)](https://travis-ci.org/php-enqueue/amqp-lib) +[![Total Downloads](https://poser.pugx.org/enqueue/amqp-lib/d/total.png)](https://packagist.org/packages/enqueue/amqp-lib) +[![Latest Stable Version](https://poser.pugx.org/enqueue/amqp-lib/version.png)](https://packagist.org/packages/enqueue/amqp-lib) + +This is an implementation of [amqp interop](https://github.com/queue-interop/amqp-interop). It uses [php-amqplib](https://github.com/php-amqplib/php-amqplib) internally. + +## Resources + +* [Documentation](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md) +* [Questions](https://gitter.im/php-enqueue/Lobby) +* [Issue Tracker](https://github.com/php-enqueue/enqueue-dev/issues) + +## Developed by Forma-Pro + +Forma-Pro is a full stack development company which interests also spread to open source development. +Being a team of strong professionals we have an aim an ability to help community by developing cutting edge solutions in the areas of e-commerce, docker & microservice oriented architecture where we have accumulated a huge many-years experience. +Our main specialization is Symfony framework based solution, but we are always looking to the technologies that allow us to do our job the best way. We are committed to creating solutions that revolutionize the way how things are developed in aspects of architecture & scalability. + +If you have any questions and inquires about our open source development, this product particularly or any other matter feel free to contact at opensource@forma-pro.com + +## License + +It is released under the [MIT License](LICENSE). \ No newline at end of file diff --git a/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php b/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php index 42ef02fbb..71597c9a7 100644 --- a/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php +++ b/pkg/amqp-lib/Tests/AmqpConnectionFactoryConfigTest.php @@ -89,6 +89,33 @@ public static function provideConfigs() // some examples from Appendix A: Examples (https://www.rabbitmq.com/uri-spec.html) + 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', [ diff --git a/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php b/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php index eb9447f95..fd455b15d 100644 --- a/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php +++ b/pkg/enqueue/Tests/Functions/DsnToConnectionFactoryFunctionTest.php @@ -32,7 +32,7 @@ public function testThrowIfDsnMissingScheme() public function testThrowIfDsnNotSupported() { $this->expectException(\LogicException::class); - $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp", "null"'); + $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp+ext"'); \Enqueue\dsn_to_connection_factory('http://schemenotsupported/'); } @@ -68,7 +68,7 @@ public static function provideDSNs() yield ['beanstalk://', PheanstalkConnectionFactory::class]; -// yield ['gearman://', GearmanConnectionFactory::class]; + // yield ['gearman://', GearmanConnectionFactory::class]; yield ['rdkafka://', RdKafkaConnectionFactory::class]; } diff --git a/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php b/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php index d088bae93..54daf8c5f 100644 --- a/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php +++ b/pkg/enqueue/Tests/Functions/DsnToContextFunctionTest.php @@ -28,7 +28,7 @@ public function testThrowIfDsnMissingScheme() public function testThrowIfDsnNotSupported() { $this->expectException(\LogicException::class); - $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp", "null"'); + $this->expectExceptionMessage('The scheme "http" is not supported. Supported "file", "amqp+ext"'); \Enqueue\dsn_to_context('http://schemenotsupported/'); } diff --git a/pkg/enqueue/functions.php b/pkg/enqueue/functions.php index b071e0279..215899c50 100644 --- a/pkg/enqueue/functions.php +++ b/pkg/enqueue/functions.php @@ -2,7 +2,9 @@ namespace Enqueue; -use Enqueue\AmqpExt\AmqpConnectionFactory; +use Enqueue\AmqpBunny\AmqpConnectionFactory as AmqpBunnyConnectionFactory; +use Enqueue\AmqpExt\AmqpConnectionFactory as AmqpExtConnectionFactory; +use Enqueue\AmqpLib\AmqpConnectionFactory as AmqpLibConnectionFactory; use Enqueue\Consumption\QueueConsumer; use Enqueue\Dbal\DbalConnectionFactory; use Enqueue\Fs\FsConnectionFactory; @@ -26,8 +28,22 @@ function dsn_to_connection_factory($dsn) $map['file'] = FsConnectionFactory::class; } - if (class_exists(AmqpConnectionFactory::class)) { - $map['amqp'] = AmqpConnectionFactory::class; + if (class_exists(AmqpExtConnectionFactory::class)) { + $map['amqp+ext'] = AmqpExtConnectionFactory::class; + } + if (class_exists(AmqpBunnyConnectionFactory::class)) { + $map['amqp+lib'] = AmqpBunnyConnectionFactory::class; + } + if (class_exists(AmqpLibConnectionFactory::class)) { + $map['amqp+bunny'] = AmqpBunnyConnectionFactory::class; + } + + if (class_exists(AmqpExtConnectionFactory::class)) { + $map['amqp'] = AmqpExtConnectionFactory::class; + } elseif (class_exists(AmqpBunnyConnectionFactory::class)) { + $map['amqp'] = AmqpBunnyConnectionFactory::class; + } elseif (class_exists(AmqpLibConnectionFactory::class)) { + $map['amqp'] = AmqpLibConnectionFactory::class; } if (class_exists(NullConnectionFactory::class)) { From d48667ce2efd66d2c55df6996f916e9c55602ad5 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 4 Aug 2017 14:46:02 +0300 Subject: [PATCH 49/76] register transport factory. --- pkg/enqueue-bundle/EnqueueBundle.php | 8 +++++++ .../Tests/Unit/EnqueueBundleTest.php | 24 +++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/pkg/enqueue-bundle/EnqueueBundle.php b/pkg/enqueue-bundle/EnqueueBundle.php index c2c9b6bbc..9f7400e40 100644 --- a/pkg/enqueue-bundle/EnqueueBundle.php +++ b/pkg/enqueue-bundle/EnqueueBundle.php @@ -2,6 +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; @@ -82,6 +85,11 @@ public function build(ContainerBuilder $container) $extension->addTransportFactory(new SqsTransportFactory()); } + if (class_exists(AmqpBunnyContext::class)) { + $extension->addTransportFactory(new AmqpBunnyTransportFactory()); + $extension->addTransportFactory(new RabbitMqAmqpBunnyTransportFactory()); + } + $container->addCompilerPass(new AsyncEventsPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); $container->addCompilerPass(new AsyncTransformersPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 100); } diff --git a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php index c989289ad..3b8d69a9d 100644 --- a/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php +++ b/pkg/enqueue-bundle/Tests/Unit/EnqueueBundleTest.php @@ -2,6 +2,8 @@ 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; @@ -224,6 +226,28 @@ public function testShouldRegisterSqsTransportFactory() $bundle->build($container); } + public function testShouldRegisterAmqpBunnyTransportFactory() + { + $extensionMock = $this->createEnqueueExtensionMock(); + + $container = new ContainerBuilder(); + $container->registerExtension($extensionMock); + + $extensionMock + ->expects($this->at(10)) + ->method('addTransportFactory') + ->with($this->isInstanceOf(AmqpBunnyTransportFactory::class)) + ; + $extensionMock + ->expects($this->at(11)) + ->method('addTransportFactory') + ->with($this->isInstanceOf(RabbitMqAmqpBunnyTransportFactory::class)) + ; + + $bundle = new EnqueueBundle(); + $bundle->build($container); + } + /** * @return \PHPUnit_Framework_MockObject_MockObject|EnqueueExtension */ From 79c098c8fed5ab090b06cbd41cdf4ef1bc4d8cc9 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 4 Aug 2017 14:51:37 +0300 Subject: [PATCH 50/76] upd docs. --- bin/dev | 2 +- docs/bundle/config_reference.md | 137 +++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 3 deletions(-) diff --git a/bin/dev b/bin/dev index d57602c96..df04fee23 100755 --- a/bin/dev +++ b/bin/dev @@ -27,7 +27,7 @@ while getopts "bustefcd" OPTION; do COMPOSE_PROJECT_NAME=mqdev docker-compose run -e CHANGELOG_GITHUB_TOKEN=${CHANGELOG_GITHUB_TOKEN:-""} --workdir="/mqdev" --rm generate-changelog github_changelog_generator --future-release "$2" --simple-list ;; - d) COMPOSE_PROJECT_NAME=mqdev docker-compose run --workdir="/mqdev" --rm dev php pkg/enqueue-bundle/Tests/Functional/app/console.php config:dump-reference enqueue + d) COMPOSE_PROJECT_NAME=mqdev docker-compose run --workdir="/mqdev" --rm dev php pkg/enqueue-bundle/Tests/Functional/app/console.php config:dump-reference enqueue -vvv ;; \?) echo "Invalid option: -$OPTARG" >&2 diff --git a/docs/bundle/config_reference.md b/docs/bundle/config_reference.md index a891d75cf..cfb08fa08 100644 --- a/docs/bundle/config_reference.md +++ b/docs/bundle/config_reference.md @@ -68,6 +68,9 @@ enqueue: write_timeout: ~ persisted: false lazy: true + + # 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: # The connection to AMQP broker set as a string. Other parameters are ignored if set @@ -99,6 +102,86 @@ enqueue: persisted: false lazy: true + # 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" + + # The option tells whether RabbitMQ broker has delay plugin installed or not + delay_plugin_installed: false + amqp_lib: + + # The connection to AMQP broker set as a string. Other parameters are ignored if set + dsn: ~ + + # The host to connect too. Note: Max 1024 characters + host: localhost + + # Port on the host. + port: 5672 + + # The user name to use. Note: Max 128 characters. + user: guest + + # Password. Note: Max 128 characters. + pass: guest + + # The virtual host on the host. Note: Max 128 characters. + vhost: / + + # Connection timeout. Note: 0 or greater seconds. May be fractional. + connection_timeout: !!float 3 + read_write_timeout: !!float 3 + + # Timeout in for income activity. Note: 0 or greater seconds. May be fractional. + read_timeout: 3 + + # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. + write_timeout: 3 + lazy: true + stream: true + insist: false + keepalive: false + + # 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 + rabbitmq_amqp_lib: + + # The connection to AMQP broker set as a string. Other parameters are ignored if set + dsn: ~ + + # The host to connect too. Note: Max 1024 characters + host: localhost + + # Port on the host. + port: 5672 + + # The user name to use. Note: Max 128 characters. + user: guest + + # Password. Note: Max 128 characters. + pass: guest + + # The virtual host on the host. Note: Max 128 characters. + vhost: / + + # Connection timeout. Note: 0 or greater seconds. May be fractional. + connection_timeout: !!float 3 + read_write_timeout: !!float 3 + + # Timeout in for income activity. Note: 0 or greater seconds. May be fractional. + read_timeout: 3 + + # Timeout in for outcome activity. Note: 0 or greater seconds. May be fractional. + write_timeout: 3 + lazy: true + stream: true + insist: false + keepalive: false + + # 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 + # The option tells whether RabbitMQ broker has delay plugin installed or not delay_plugin_installed: false fs: @@ -155,11 +238,62 @@ enqueue: # the connection will be performed as later as possible, if the option set to true lazy: true + amqp_bunny: + + # The connection to AMQP broker set as a string. Other parameters are ignored if set + dsn: ~ + + # The host to connect too. Note: Max 1024 characters + host: localhost + + # Port on the host. + port: 5672 + + # The user name to use. Note: Max 128 characters. + user: guest + + # Password. Note: Max 128 characters. + pass: guest + + # The virtual host on the host. Note: Max 128 characters. + vhost: / + lazy: true + + # 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 + rabbitmq_amqp_bunny: + + # The connection to AMQP broker set as a string. Other parameters are ignored if set + dsn: ~ + + # The host to connect too. Note: Max 1024 characters + host: localhost + + # Port on the host. + port: 5672 + + # The user name to use. Note: Max 128 characters. + user: guest + + # Password. Note: Max 128 characters. + pass: guest + + # The virtual host on the host. Note: Max 128 characters. + vhost: / + lazy: true + + # 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 + + # The option tells whether RabbitMQ broker has delay plugin installed or not + delay_plugin_installed: false client: traceable_producer: false prefix: enqueue app_name: app - router_topic: router + router_topic: default router_queue: default router_processor: enqueue.client.router_processor default_processor_queue: default @@ -167,7 +301,6 @@ enqueue: job: false async_events: enabled: false - spool_producer: false extensions: doctrine_ping_connection_extension: false doctrine_clear_identity_map_extension: false From fa6ed4857dd43b5d692833843d55f764aeb4da19 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 4 Aug 2017 15:02:54 +0300 Subject: [PATCH 51/76] add amqp bunny to dev scripts. --- bin/release | 2 +- bin/subtree-split | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/release b/bin/release index a47c40aea..de8de6018 100755 --- a/bin/release +++ b/bin/release @@ -14,7 +14,7 @@ fi CURRENT_BRANCH=`git rev-parse --abbrev-ref HEAD` -for REMOTE in origin stomp amqp-ext amqp-lib pheanstalk gearman sqs fs redis dbal null rdkafka enqueue simple-client enqueue-bundle job-queue test async-event-dispatcher +for REMOTE in origin stomp amqp-ext amqp-lib amqp-bunny pheanstalk gearman sqs fs redis dbal null rdkafka enqueue simple-client enqueue-bundle job-queue test async-event-dispatcher do echo "" echo "" diff --git a/bin/subtree-split b/bin/subtree-split index d04e6f2aa..24dfb4768 100755 --- a/bin/subtree-split +++ b/bin/subtree-split @@ -48,6 +48,7 @@ remote simple-client git@github.com:php-enqueue/simple-client.git remote stomp git@github.com:php-enqueue/stomp.git remote amqp-ext git@github.com:php-enqueue/amqp-ext.git remote amqp-lib git@github.com:php-enqueue/amqp-lib.git +remote amqp-bunny git@github.com:php-enqueue/amqp-bunny.git remote pheanstalk git@github.com:php-enqueue/pheanstalk.git remote gearman git@github.com:php-enqueue/gearman.git remote fs git@github.com:php-enqueue/fs.git @@ -66,6 +67,7 @@ split 'pkg/simple-client' simple-client split 'pkg/stomp' stomp split 'pkg/amqp-ext' amqp-ext split 'pkg/amqp-lib' amqp-lib +split 'pkg/amqp-bunny' amqp-bunny split 'pkg/pheanstalk' pheanstalk split 'pkg/gearman' gearman split 'pkg/rdkafka' rdkafka From 02b003b4d3174284d7a418f91b6a9b280624b692 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 4 Aug 2017 15:04:10 +0300 Subject: [PATCH 52/76] fix doc links --- README.md | 2 +- docs/index.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 54422d16c..0a27fc228 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Features: * [Feature rich](docs/quick_tour.md). * Implements [JMS](https://docs.oracle.com/javaee/7/api/javax/jms/package-summary.html) like transports based on a[queue-interop](https://github.com/queue-interop/queue-interop) interfaces. * Supported transports - * AMQP based on [the ext](docs/transport/amqp.md), [the lib](docs/transport/amqp_lib.md) + * Amqp based on [the ext](docs/transport/amqp.md), [bunny](docs/transport/amqp_bunny.md), [the lib](docs/transport/amqp_lib.md) * [Beanstalk](docs/transport/pheanstalk.md) * [STOMP](docs/transport/stomp.md) * [Amazon SQS](docs/transport/sqs.md) diff --git a/docs/index.md b/docs/index.md index 558f61206..f352c6beb 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,7 +2,7 @@ * [Quick tour](quick_tour.md) * Transports - - Amqp based on [the ext](docs/transport/amqp.md), [bunny](docs/transport/amqp_bunny.md), [the lib](docs/transport/amqp_lib.md) + - Amqp based on [the ext](transport/amqp.md), [bunny](transport/amqp_bunny.md), [the lib](transport/amqp_lib.md) - [Amazon SQS](transport/sqs.md) - [Beanstalk (Pheanstalk)](transport/pheanstalk.md) - [Gearman](transport/gearman.md) From f866f01f1b30375988a9fb6a977640779d6c553b Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 4 Aug 2017 15:12:01 +0300 Subject: [PATCH 53/76] [bunle] require amqp-bunny lib --- pkg/enqueue-bundle/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/enqueue-bundle/composer.json b/pkg/enqueue-bundle/composer.json index f70ab6af8..9d1f50435 100644 --- a/pkg/enqueue-bundle/composer.json +++ b/pkg/enqueue-bundle/composer.json @@ -23,6 +23,7 @@ "enqueue/amqp-ext": "^0.7@dev", "php-amqplib/php-amqplib": "^2.7@dev", "enqueue/amqp-lib": "^0.7@dev", + "enqueue/amqp-bunny": "^0.7@dev", "enqueue/job-queue": "^0.7@dev", "enqueue/fs": "^0.7@dev", "enqueue/redis": "^0.7@dev", From 4f65c8790ecf4e61927b7e5adbfc02e2f06b5783 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Fri, 4 Aug 2017 15:19:28 +0300 Subject: [PATCH 54/76] delay strategy --- composer.json | 5 ++ pkg/amqp-lib/AmqpConnectionFactory.php | 11 +++- pkg/amqp-lib/AmqpContext.php | 13 +++-- pkg/amqp-lib/AmqpProducer.php | 32 +++++++++-- .../Amqp => amqp-tools}/DelayStrategy.php | 5 +- pkg/amqp-tools/DelayStrategyAware.php | 11 ++++ pkg/amqp-tools/DelayStrategyAwareTrait.php | 19 +++++++ .../RabbitMQDelayPluginDelayStrategy.php | 54 +++++++++++++++++++ .../RabbitMQDlxDelayStrategy.php} | 20 +++---- pkg/amqp-tools/composer.json | 35 ++++++++++++ .../Client/Amqp/DelayPluginDelayStrategy.php | 43 --------------- 11 files changed, 184 insertions(+), 64 deletions(-) rename pkg/{enqueue/Client/Amqp => amqp-tools}/DelayStrategy.php (73%) create mode 100644 pkg/amqp-tools/DelayStrategyAware.php create mode 100644 pkg/amqp-tools/DelayStrategyAwareTrait.php create mode 100644 pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php rename pkg/{enqueue/Client/Amqp/DlxDelayStrategy.php => amqp-tools/RabbitMQDlxDelayStrategy.php} (73%) create mode 100644 pkg/amqp-tools/composer.json delete mode 100644 pkg/enqueue/Client/Amqp/DelayPluginDelayStrategy.php diff --git a/composer.json b/composer.json index 66573eaf8..b91be6d9c 100644 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "enqueue/stomp": "*@dev", "enqueue/amqp-ext": "*@dev", "enqueue/amqp-lib": "*@dev", + "enqueue/amqp-tools": "*@dev", "php-amqplib/php-amqplib": "^2.7@dev", "enqueue/redis": "*@dev", "enqueue/fs": "*@dev", @@ -79,6 +80,10 @@ "type": "path", "url": "pkg/amqp-lib" }, + { + "type": "path", + "url": "pkg/amqp-tools" + }, { "type": "path", "url": "pkg/redis" diff --git a/pkg/amqp-lib/AmqpConnectionFactory.php b/pkg/amqp-lib/AmqpConnectionFactory.php index cbee87991..d8f072a74 100644 --- a/pkg/amqp-lib/AmqpConnectionFactory.php +++ b/pkg/amqp-lib/AmqpConnectionFactory.php @@ -2,6 +2,8 @@ namespace Enqueue\AmqpLib; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory; use PhpAmqpLib\Connection\AbstractConnection; use PhpAmqpLib\Connection\AMQPLazyConnection; @@ -9,8 +11,10 @@ use PhpAmqpLib\Connection\AMQPSocketConnection; use PhpAmqpLib\Connection\AMQPStreamConnection; -class AmqpConnectionFactory implements InteropAmqpConnectionFactory +class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var array */ @@ -72,7 +76,10 @@ public function __construct($config = 'amqp://') */ public function createContext() { - return new AmqpContext($this->establishConnection(), $this->config); + $context = new AmqpContext($this->establishConnection(), $this->config); + $context->setDelayStrategy($this->delayStrategy); + + return $context; } /** diff --git a/pkg/amqp-lib/AmqpContext.php b/pkg/amqp-lib/AmqpContext.php index dcece273d..1a82bb317 100644 --- a/pkg/amqp-lib/AmqpContext.php +++ b/pkg/amqp-lib/AmqpContext.php @@ -2,6 +2,8 @@ namespace Enqueue\AmqpLib; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpBind as InteropAmqpBind; use Interop\Amqp\AmqpContext as InteropAmqpContext; use Interop\Amqp\AmqpMessage as InteropAmqpMessage; @@ -19,8 +21,10 @@ use PhpAmqpLib\Connection\AbstractConnection; use PhpAmqpLib\Wire\AMQPTable; -class AmqpContext implements InteropAmqpContext +class AmqpContext implements InteropAmqpContext, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var AbstractConnection */ @@ -117,7 +121,10 @@ public function createConsumer(PsrDestination $destination) */ public function createProducer() { - return new AmqpProducer($this->getChannel()); + $producer = new AmqpProducer($this->getChannel(), $this); + $producer->setDelayStrategy($this->delayStrategy); + + return $producer; } /** @@ -146,7 +153,7 @@ public function declareTopic(InteropAmqpTopic $topic) (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_AUTODELETE), (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_INTERNAL), (bool) ($topic->getFlags() & InteropAmqpTopic::FLAG_NOWAIT), - $topic->getArguments() + $topic->getArguments() ? new AMQPTable($topic->getArguments()) : null ); } diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php index c5d8c0927..7da4b6acc 100644 --- a/pkg/amqp-lib/AmqpProducer.php +++ b/pkg/amqp-lib/AmqpProducer.php @@ -2,6 +2,8 @@ namespace Enqueue\AmqpLib; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpMessage as InteropAmqpMessage; use Interop\Amqp\AmqpProducer as InteropAmqpProducer; use Interop\Amqp\AmqpQueue as InteropAmqpQueue; @@ -16,8 +18,10 @@ use PhpAmqpLib\Message\AMQPMessage as LibAMQPMessage; use PhpAmqpLib\Wire\AMQPTable; -class AmqpProducer implements InteropAmqpProducer +class AmqpProducer implements InteropAmqpProducer, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var int|null */ @@ -28,17 +32,29 @@ class AmqpProducer implements InteropAmqpProducer */ private $timeToLive; + /** + * @var int + */ + private $deliveryDelay; + /** * @var AMQPChannel */ private $channel; + /** + * @var AmqpContext + */ + private $context; + /** * @param AMQPChannel $channel + * @param AmqpContext $context */ - public function __construct(AMQPChannel $channel) + public function __construct(AMQPChannel $channel, AmqpContext $context) { $this->channel = $channel; + $this->context = $context; } /** @@ -70,7 +86,9 @@ public function send(PsrDestination $destination, PsrMessage $message) $amqpMessage = new LibAMQPMessage($message->getBody(), $amqpProperties); - if ($destination instanceof InteropAmqpTopic) { + if ($this->deliveryDelay) { + $this->delayStrategy->delayMessage($this->context, $destination, $message, $this->deliveryDelay); + } elseif ($destination instanceof InteropAmqpTopic) { $this->channel->basic_publish( $amqpMessage, $destination->getTopicName(), @@ -94,7 +112,11 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); + if (null === $this->delayStrategy) { + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); + } + + $this->deliveryDelay = $deliveryDelay; } /** @@ -102,7 +124,7 @@ public function setDeliveryDelay($deliveryDelay) */ public function getDeliveryDelay() { - return null; + return $this->deliveryDelay; } /** diff --git a/pkg/enqueue/Client/Amqp/DelayStrategy.php b/pkg/amqp-tools/DelayStrategy.php similarity index 73% rename from pkg/enqueue/Client/Amqp/DelayStrategy.php rename to pkg/amqp-tools/DelayStrategy.php index de222190e..ba1bcc3d2 100644 --- a/pkg/enqueue/Client/Amqp/DelayStrategy.php +++ b/pkg/amqp-tools/DelayStrategy.php @@ -1,6 +1,6 @@ delayStrategy = $delayStrategy; + } +} diff --git a/pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php b/pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php new file mode 100644 index 000000000..4ad3ec453 --- /dev/null +++ b/pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php @@ -0,0 +1,54 @@ +createMessage($message->getBody(), $message->getProperties(), $message->getHeaders()); + $delayMessage->setProperty('x-delay', (int) $delayMsec); + $delayMessage->setRoutingKey($message->getRoutingKey()); + + if ($dest instanceof AmqpTopic) { + $delayTopic = $context->createTopic('enqueue.'.$dest->getTopicName().'.delayed'); + $delayTopic->setType('x-delayed-message'); + $delayTopic->addFlag($dest->getFlags()); + $delayTopic->setArgument('x-delayed-type', $dest->getType()); + + $context->declareTopic($delayTopic); + $context->bind(new AmqpBind($dest, $delayTopic, $delayMessage->getRoutingKey())); + } elseif ($dest instanceof AmqpQueue) { + $delayTopic = $context->createTopic('enqueue.queue.delayed'); + $delayTopic->setType('x-delayed-message'); + $delayTopic->addFlag(AmqpTopic::FLAG_DURABLE); + $delayTopic->setArgument('x-delayed-type', AmqpTopic::TYPE_DIRECT); + + $delayMessage->setRoutingKey($dest->getQueueName()); + + $context->declareTopic($delayTopic); + $context->bind(new AmqpBind($dest, $delayTopic, $delayMessage->getRoutingKey())); + } else { + throw new InvalidDestinationException(sprintf('The destination must be an instance of %s but got %s.', + AmqpTopic::class.'|'.AmqpQueue::class, + get_class($dest) + )); + } + + $producer = $context->createProducer(); + $producer->setDelayStrategy(null); + + $producer->send($delayTopic, $delayMessage); + } +} diff --git a/pkg/enqueue/Client/Amqp/DlxDelayStrategy.php b/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php similarity index 73% rename from pkg/enqueue/Client/Amqp/DlxDelayStrategy.php rename to pkg/amqp-tools/RabbitMQDlxDelayStrategy.php index 14812bba5..d609e70d6 100644 --- a/pkg/enqueue/Client/Amqp/DlxDelayStrategy.php +++ b/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php @@ -1,33 +1,35 @@ getDelay(); - if ($dest instanceof AmqpTopic) { - $delayQueue = $context->createQueue($dest->getTopicName().'.'.$delaySec.'.x.delayed'); + $delayQueue = $context->createQueue($dest->getTopicName().'.'.$delayMsec.'.x.delayed'); $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE); $delayQueue->setArgument('x-dead-letter-exchange', $dest->getTopicName()); } elseif ($dest instanceof AmqpQueue) { - $delayQueue = $context->createQueue($dest->getQueueName().'.'.$delaySec.'.delayed'); + $delayQueue = $context->createQueue($dest->getQueueName().'.'.$delayMsec.'.delayed'); $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE); $delayQueue->setArgument('x-dead-letter-exchange', ''); $delayQueue->setArgument('x-dead-letter-routing-key', $dest->getQueueName()); } else { - throw new \LogicException(); + throw new InvalidDestinationException(sprintf('The destination must be an instance of %s but got %s.', + AmqpTopic::class.'|'.AmqpQueue::class, + get_class($dest) + )); } $context->declareQueue($delayQueue); @@ -40,7 +42,7 @@ public function delayMessage(AmqpContext $context, AmqpDestination $dest, AmqpMe unset($properties['x-death']); $delayMessage = $context->createMessage($message->getBody(), $properties, $message->getHeaders()); - $delayMessage->setExpiration((string) ($delaySec * 1000)); + $delayMessage->setExpiration((string) $delayMsec); $context->createProducer()->send($delayQueue, $delayMessage); } diff --git a/pkg/amqp-tools/composer.json b/pkg/amqp-tools/composer.json new file mode 100644 index 000000000..8ebc33de6 --- /dev/null +++ b/pkg/amqp-tools/composer.json @@ -0,0 +1,35 @@ +{ + "name": "enqueue/amqp-tools", + "type": "library", + "description": "Message Queue Amqp Tools", + "keywords": ["messaging", "queue", "amqp"], + "license": "MIT", + "repositories": [ + { + "type": "vcs", + "url": "git@github.com:php-enqueue/test.git" + } + ], + "require": { + "php": ">=5.6", + "queue-interop/queue-interop": "^0.6@dev", + "queue-interop/amqp-interop": "^0.6@dev" + }, + "require-dev": { + "phpunit/phpunit": "~5.4.0", + "enqueue/test": "^0.7@dev", + "enqueue/null": "^0.7@dev" + }, + "autoload": { + "psr-4": { "Enqueue\\AmqpTools\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "0.7.x-dev" + } + } +} diff --git a/pkg/enqueue/Client/Amqp/DelayPluginDelayStrategy.php b/pkg/enqueue/Client/Amqp/DelayPluginDelayStrategy.php deleted file mode 100644 index b4959b5fa..000000000 --- a/pkg/enqueue/Client/Amqp/DelayPluginDelayStrategy.php +++ /dev/null @@ -1,43 +0,0 @@ -getDelay(); - - if ($dest instanceof AmqpTopic) { - $delayTopic = $context->createTopic($dest->getTopicName().'.x.delayed'); - $delayTopic->setType('x-delayed-message'); - $delayTopic->addFlag(AmqpTopic::FLAG_DURABLE); - $delayTopic->setArgument('x-delayed-type', AmqpTopic::TYPE_DIRECT); - - $context->declareTopic($delayTopic); - $context->bind(new AmqpBind($dest, $delayTopic)); - } elseif ($dest instanceof AmqpQueue) { - $delayTopic = $context->createTopic($dest->getQueueName().'.delayed'); - $delayTopic->setType('x-delayed-message'); - $delayTopic->addFlag(AmqpTopic::FLAG_DURABLE); - $delayTopic->setArgument('x-delayed-type', AmqpTopic::TYPE_DIRECT); - - $context->declareTopic($delayTopic); - $context->bind(new AmqpBind($delayTopic, $dest, $dest->getQueueName())); - } else { - throw new \LogicException(); - } - - $delayMessage = $context->createMessage($message->getBody(), $message->getProperties(), $message->getHeaders()); - $delayMessage->setProperty('x-delay', (string) ($delaySec * 1000)); - - $context->createProducer()->send($delayTopic, $delayMessage); - } -} From 8c0385a9c4b5f3aac07f027032d6461c3808840e Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Fri, 4 Aug 2017 16:28:03 +0300 Subject: [PATCH 55/76] delay strategy --- pkg/amqp-tools/RabbitMQDlxDelayStrategy.php | 29 ++++++++++++--------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php b/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php index d609e70d6..9ca2ba506 100644 --- a/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php +++ b/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php @@ -16,12 +16,27 @@ class RabbitMQDlxDelayStrategy implements DelayStrategy */ public function delayMessage(AmqpContext $context, AmqpDestination $dest, AmqpMessage $message, $delayMsec) { + $properties = $message->getProperties(); + + // The x-death header must be removed because of the bug in RabbitMQ. + // It was reported that the bug is fixed since 3.5.4 but I tried with 3.6.1 and the bug still there. + // https://github.com/rabbitmq/rabbitmq-server/issues/216 + unset($properties['x-death']); + + $delayMessage = $context->createMessage($message->getBody(), $properties, $message->getHeaders()); + $delayMessage->setExpiration((int) $delayMsec); + $delayMessage->setRoutingKey($message->getRoutingKey()); + if ($dest instanceof AmqpTopic) { - $delayQueue = $context->createQueue($dest->getTopicName().'.'.$delayMsec.'.x.delayed'); + $routingKey = $message->getRoutingKey() ? '.'.$message->getRoutingKey() : ''; + $name = sprintf('enqueue.%s%s.%s.x.delay', $dest->getTopicName(), $routingKey, $delayMsec); + + $delayQueue = $context->createQueue($name); $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE); $delayQueue->setArgument('x-dead-letter-exchange', $dest->getTopicName()); + $delayQueue->setArgument('x-dead-letter-routing-key', (string) $delayMessage->getRoutingKey()); } elseif ($dest instanceof AmqpQueue) { - $delayQueue = $context->createQueue($dest->getQueueName().'.'.$delayMsec.'.delayed'); + $delayQueue = $context->createQueue('enqueue.'.$dest->getQueueName().'.'.$delayMsec.'.delayed'); $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE); $delayQueue->setArgument('x-dead-letter-exchange', ''); $delayQueue->setArgument('x-dead-letter-routing-key', $dest->getQueueName()); @@ -34,16 +49,6 @@ public function delayMessage(AmqpContext $context, AmqpDestination $dest, AmqpMe $context->declareQueue($delayQueue); - $properties = $message->getProperties(); - - // The x-death header must be removed because of the bug in RabbitMQ. - // It was reported that the bug is fixed since 3.5.4 but I tried with 3.6.1 and the bug still there. - // https://github.com/rabbitmq/rabbitmq-server/issues/216 - unset($properties['x-death']); - - $delayMessage = $context->createMessage($message->getBody(), $properties, $message->getHeaders()); - $delayMessage->setExpiration((string) $delayMsec); - $context->createProducer()->send($delayQueue, $delayMessage); } } From 20c030d0814775b46624cb8f3f0249d1995d46b7 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Fri, 4 Aug 2017 16:42:11 +0300 Subject: [PATCH 56/76] delay strategy --- pkg/amqp-ext/AmqpConnectionFactory.php | 16 +++++++++-- pkg/amqp-ext/AmqpContext.php | 11 ++++++-- pkg/amqp-ext/AmqpProducer.php | 32 ++++++++++++++++++---- pkg/amqp-tools/DelayStrategyAwareTrait.php | 2 +- 4 files changed, 50 insertions(+), 11 deletions(-) diff --git a/pkg/amqp-ext/AmqpConnectionFactory.php b/pkg/amqp-ext/AmqpConnectionFactory.php index 537cb94c5..4ee03ff15 100644 --- a/pkg/amqp-ext/AmqpConnectionFactory.php +++ b/pkg/amqp-ext/AmqpConnectionFactory.php @@ -2,10 +2,14 @@ namespace Enqueue\AmqpExt; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory; -class AmqpConnectionFactory implements InteropAmqpConnectionFactory +class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var array */ @@ -79,12 +83,18 @@ public function __construct($config = 'amqp://') public function createContext() { if ($this->config['lazy']) { - return new AmqpContext(function () { + $context = new AmqpContext(function () { return $this->createExtContext($this->establishConnection()); }, $this->config['receive_method']); + $context->setDelayStrategy($this->delayStrategy); + + return $context; } - return new AmqpContext($this->createExtContext($this->establishConnection()), $this->config['receive_method']); + $context = new AmqpContext($this->createExtContext($this->establishConnection()), $this->config['receive_method']); + $context->setDelayStrategy($this->delayStrategy); + + return $context; } /** diff --git a/pkg/amqp-ext/AmqpContext.php b/pkg/amqp-ext/AmqpContext.php index 32a135b18..6d2d4e38f 100644 --- a/pkg/amqp-ext/AmqpContext.php +++ b/pkg/amqp-ext/AmqpContext.php @@ -2,6 +2,8 @@ namespace Enqueue\AmqpExt; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpBind as InteropAmqpBind; use Interop\Amqp\AmqpContext as InteropAmqpContext; use Interop\Amqp\AmqpQueue as InteropAmqpQueue; @@ -15,8 +17,10 @@ use Interop\Queue\PsrDestination; use Interop\Queue\PsrTopic; -class AmqpContext implements InteropAmqpContext +class AmqpContext implements InteropAmqpContext, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var \AMQPChannel */ @@ -217,7 +221,10 @@ public function createTemporaryQueue() */ public function createProducer() { - return new AmqpProducer($this->getExtChannel()); + $producer = new AmqpProducer($this->getExtChannel(), $this); + $producer->setDelayStrategy($this->delayStrategy); + + return $producer; } /** diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index 4ed1845c9..456da6bfd 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -2,6 +2,8 @@ namespace Enqueue\AmqpExt; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpMessage; use Interop\Amqp\AmqpProducer as InteropAmqpProducer; use Interop\Amqp\AmqpQueue; @@ -13,8 +15,10 @@ use Interop\Queue\PsrMessage; use Interop\Queue\PsrTopic; -class AmqpProducer implements InteropAmqpProducer +class AmqpProducer implements InteropAmqpProducer, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var int|null */ @@ -30,12 +34,24 @@ class AmqpProducer implements InteropAmqpProducer */ private $amqpChannel; + /** + * @var AmqpContext + */ + private $context; + + /** + * @var int + */ + private $deliveryDelay; + /** * @param \AMQPChannel $ampqChannel + * @param AmqpContext $context */ - public function __construct(\AMQPChannel $ampqChannel) + public function __construct(\AMQPChannel $ampqChannel, AmqpContext $context) { $this->amqpChannel = $ampqChannel; + $this->context = $context; } /** @@ -67,7 +83,9 @@ public function send(PsrDestination $destination, PsrMessage $message) $amqpAttributes['headers'] = $message->getProperties(); } - if ($destination instanceof AmqpTopic) { + if ($this->deliveryDelay) { + $this->delayStrategy->delayMessage($this->context, $destination, $message, $this->deliveryDelay); + } elseif ($destination instanceof AmqpTopic) { $amqpExchange = new \AMQPExchange($this->amqpChannel); $amqpExchange->setType($destination->getType()); $amqpExchange->setName($destination->getTopicName()); @@ -99,7 +117,11 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); + if (null === $this->delayStrategy) { + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); + } + + $this->deliveryDelay = $deliveryDelay; } /** @@ -107,7 +129,7 @@ public function setDeliveryDelay($deliveryDelay) */ public function getDeliveryDelay() { - return null; + return $this->deliveryDelay; } /** diff --git a/pkg/amqp-tools/DelayStrategyAwareTrait.php b/pkg/amqp-tools/DelayStrategyAwareTrait.php index aeae7bf8f..8313b4d49 100644 --- a/pkg/amqp-tools/DelayStrategyAwareTrait.php +++ b/pkg/amqp-tools/DelayStrategyAwareTrait.php @@ -10,7 +10,7 @@ trait DelayStrategyAwareTrait protected $delayStrategy; /** - * {@inheritdoc} + * @param DelayStrategy|null $delayStrategy */ public function setDelayStrategy(DelayStrategy $delayStrategy = null) { From 0a5f8c503791102f72c8d516846ed0a5730aae2f Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Fri, 4 Aug 2017 16:58:37 +0300 Subject: [PATCH 57/76] [producer] do not throw exception if feature not implemented and null is set. It applies to the case where the featuer is not supported too. --- pkg/amqp-bunny/AmqpProducer.php | 4 ++++ pkg/amqp-ext/AmqpProducer.php | 4 ++++ pkg/amqp-lib/AmqpProducer.php | 4 ++++ pkg/dbal/DbalProducer.php | 12 ++++++++++++ pkg/fs/FsProducer.php | 8 ++++++++ pkg/gearman/GearmanProducer.php | 12 ++++++++++++ pkg/pheanstalk/PheanstalkProducer.php | 12 ++++++++++++ pkg/rdkafka/RdKafkaProducer.php | 12 ++++++++++++ pkg/redis/RedisProducer.php | 12 ++++++++++++ pkg/sqs/SqsProducer.php | 8 ++++++++ pkg/stomp/StompProducer.php | 12 ++++++++++++ 11 files changed, 100 insertions(+) diff --git a/pkg/amqp-bunny/AmqpProducer.php b/pkg/amqp-bunny/AmqpProducer.php index 9a19cd970..9d701bbe2 100644 --- a/pkg/amqp-bunny/AmqpProducer.php +++ b/pkg/amqp-bunny/AmqpProducer.php @@ -92,6 +92,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); } diff --git a/pkg/amqp-ext/AmqpProducer.php b/pkg/amqp-ext/AmqpProducer.php index 4ed1845c9..04d96bbb5 100644 --- a/pkg/amqp-ext/AmqpProducer.php +++ b/pkg/amqp-ext/AmqpProducer.php @@ -99,6 +99,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); } diff --git a/pkg/amqp-lib/AmqpProducer.php b/pkg/amqp-lib/AmqpProducer.php index c5d8c0927..c31b4a23b 100644 --- a/pkg/amqp-lib/AmqpProducer.php +++ b/pkg/amqp-lib/AmqpProducer.php @@ -94,6 +94,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); } diff --git a/pkg/dbal/DbalProducer.php b/pkg/dbal/DbalProducer.php index 99657041c..4d125bb10 100644 --- a/pkg/dbal/DbalProducer.php +++ b/pkg/dbal/DbalProducer.php @@ -91,6 +91,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw new \LogicException('Not implemented'); } @@ -107,6 +111,10 @@ public function getDeliveryDelay() */ public function setPriority($priority) { + if (null === $priority) { + return; + } + throw new \LogicException('Not implemented'); } @@ -123,6 +131,10 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { + if (null === $timeToLive) { + return; + } + throw new \LogicException('Not implemented'); } diff --git a/pkg/fs/FsProducer.php b/pkg/fs/FsProducer.php index 5ab27db22..a8dbac925 100644 --- a/pkg/fs/FsProducer.php +++ b/pkg/fs/FsProducer.php @@ -73,6 +73,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); } @@ -89,6 +93,10 @@ public function getDeliveryDelay() */ public function setPriority($priority) { + if (null === $priority) { + return; + } + throw PriorityNotSupportedException::providerDoestNotSupportIt(); } diff --git a/pkg/gearman/GearmanProducer.php b/pkg/gearman/GearmanProducer.php index a891ecd43..73a2c073b 100644 --- a/pkg/gearman/GearmanProducer.php +++ b/pkg/gearman/GearmanProducer.php @@ -47,6 +47,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw new \LogicException('Not implemented'); } @@ -63,6 +67,10 @@ public function getDeliveryDelay() */ public function setPriority($priority) { + if (null === $priority) { + return; + } + throw new \LogicException('Not implemented'); } @@ -79,6 +87,10 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { + if (null === $timeToLive) { + return; + } + throw new \LogicException('Not implemented'); } diff --git a/pkg/pheanstalk/PheanstalkProducer.php b/pkg/pheanstalk/PheanstalkProducer.php index d9fe8912d..08255e170 100644 --- a/pkg/pheanstalk/PheanstalkProducer.php +++ b/pkg/pheanstalk/PheanstalkProducer.php @@ -57,6 +57,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw new \LogicException('Not implemented'); } @@ -73,6 +77,10 @@ public function getDeliveryDelay() */ public function setPriority($priority) { + if (null === $priority) { + return; + } + throw new \LogicException('Not implemented'); } @@ -89,6 +97,10 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { + if (null === $timeToLive) { + return; + } + throw new \LogicException('Not implemented'); } diff --git a/pkg/rdkafka/RdKafkaProducer.php b/pkg/rdkafka/RdKafkaProducer.php index 780f72646..ffad80075 100644 --- a/pkg/rdkafka/RdKafkaProducer.php +++ b/pkg/rdkafka/RdKafkaProducer.php @@ -48,6 +48,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw new \LogicException('Not implemented'); } @@ -64,6 +68,10 @@ public function getDeliveryDelay() */ public function setPriority($priority) { + if (null === $priority) { + return; + } + throw new \LogicException('Not implemented'); } @@ -80,6 +88,10 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { + if (null === $timeToLive) { + return; + } + throw new \LogicException('Not implemented'); } diff --git a/pkg/redis/RedisProducer.php b/pkg/redis/RedisProducer.php index 1860288d0..e34506b3a 100644 --- a/pkg/redis/RedisProducer.php +++ b/pkg/redis/RedisProducer.php @@ -42,6 +42,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw new \LogicException('Not implemented'); } @@ -58,6 +62,10 @@ public function getDeliveryDelay() */ public function setPriority($priority) { + if (null === $priority) { + return; + } + throw new \LogicException('Not implemented'); } @@ -74,6 +82,10 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { + if (null === $timeToLive) { + return; + } + throw new \LogicException('Not implemented'); } diff --git a/pkg/sqs/SqsProducer.php b/pkg/sqs/SqsProducer.php index ad334e100..3acdce608 100644 --- a/pkg/sqs/SqsProducer.php +++ b/pkg/sqs/SqsProducer.php @@ -108,6 +108,10 @@ public function getDeliveryDelay() */ public function setPriority($priority) { + if (null === $priority) { + return; + } + throw PriorityNotSupportedException::providerDoestNotSupportIt(); } @@ -124,6 +128,10 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { + if (null === $timeToLive) { + return; + } + throw TimeToLiveNotSupportedException::providerDoestNotSupportIt(); } diff --git a/pkg/stomp/StompProducer.php b/pkg/stomp/StompProducer.php index e5206419c..8e386fc3b 100644 --- a/pkg/stomp/StompProducer.php +++ b/pkg/stomp/StompProducer.php @@ -50,6 +50,10 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { + if (null === $deliveryDelay) { + return; + } + throw new \LogicException('Not implemented'); } @@ -66,6 +70,10 @@ public function getDeliveryDelay() */ public function setPriority($priority) { + if (null === $priority) { + return; + } + throw new \LogicException('Not implemented'); } @@ -82,6 +90,10 @@ public function getPriority() */ public function setTimeToLive($timeToLive) { + if (null === $timeToLive) { + return; + } + throw new \LogicException('Not implemented'); } From e16b051c6c3fe42acfc498e1ca0596400d7cc0a1 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 7 Aug 2017 12:02:46 +0300 Subject: [PATCH 58/76] [doc] add elastica populate bundle --- .../populate-command-optimization.md | 114 ++++++++++++++++++ docs/index.md | 9 +- 2 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 docs/elastica-bundle/populate-command-optimization.md diff --git a/docs/elastica-bundle/populate-command-optimization.md b/docs/elastica-bundle/populate-command-optimization.md new file mode 100644 index 000000000..8c5cab739 --- /dev/null +++ b/docs/elastica-bundle/populate-command-optimization.md @@ -0,0 +1,114 @@ +# Enqueue Elastica Bundle + +Improves performance of `fos:elastica:populate` commands by distributing the work among consumers. +The performance gain depends on how much consumers you run. +For example 10 consumers may give you 5 to 7 times better performance. + +## Installation + +Install packages using [composer](https://getcomposer.org/) + +```bash +$ composer require enqueue/elastica-bundle friendsofsymfony/elastica-bundle +``` + +Add bundles to `AppKernel` + +```php + Date: Mon, 7 Aug 2017 12:05:24 +0300 Subject: [PATCH 59/76] Update index.md --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index a38c67e39..f007603f5 100644 --- a/docs/index.md +++ b/docs/index.md @@ -42,7 +42,7 @@ * Magento - [Quick tour](magento/quick_tour.md) - [Cli commands](magento/cli_commands.md) -* [Use cases] +* [Use cases](#use-cases) - [FOSElasticaBundle. Populate command optimizations](elastica-bundle/populate-command-optimization.md) - [Symfony. Async event dispatcher](async_event_dispatcher/quick_tour.md) * Development From bb183aaf40c9217472928a500b1e5bd94117e3ca Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 7 Aug 2017 12:07:01 +0300 Subject: [PATCH 60/76] Update index.md --- docs/index.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/index.md b/docs/index.md index f007603f5..474b25d2d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,7 @@ # Documentation. * [Quick tour](quick_tour.md) -* Transports +* [Transports](#transports) - Amqp based on [the ext](transport/amqp.md), [bunny](transport/amqp_bunny.md), [the lib](transport/amqp_lib.md) - [Amazon SQS](transport/sqs.md) - [Beanstalk (Pheanstalk)](transport/pheanstalk.md) @@ -12,19 +12,19 @@ - [Doctrine DBAL](transport/dbal.md) - [Filesystem](transport/filesystem.md) - [Null](transport/null.md) -* Consumption +* [Consumption](#consumption) - [Extensions](consumption/extensions.md) - [Message processor](consumption/message_processor.md) -* Client +* [Client](#client) - [Quick tour](client/quick_tour.md) - [Message examples](client/message_examples.md) - [Supported brokers](client/supported_brokers.md) - [Message bus](client/message_bus.md) - [RPC call](client/rpc_call.md) -* Job queue +* [Job queue](#job-queue) - [Run unique job](job_queue/run_unique_job.md) - [Run sub job(s)](job_queue/run_sub_job.md) -* EnqueueBundle (Symfony). +* [EnqueueBundle (Symfony)](#enqueue-bundle-symfony). - [Quick tour](bundle/quick_tour.md) - [Config reference](bundle/config_reference.md) - [Cli commands](bundle/cli_commands.md) @@ -36,16 +36,16 @@ - [Production settings](bundle/production_settings.md) - [Debuging](bundle/debuging.md) - [Functional testing](bundle/functional_testing.md) -* Laravel +* [Laravel](#laravel) - [Quick tour](laravel/quick_tour.md) - [Queues](laravel/queues.md) -* Magento +* [Magento](#magento) - [Quick tour](magento/quick_tour.md) - [Cli commands](magento/cli_commands.md) * [Use cases](#use-cases) - [FOSElasticaBundle. Populate command optimizations](elastica-bundle/populate-command-optimization.md) - [Symfony. Async event dispatcher](async_event_dispatcher/quick_tour.md) -* Development +* [Development](#development) - [Contribution](contribution.md) # Blogs From 217a9a568ae2b466c489139ecde91b00ed3b3a7f Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 7 Aug 2017 12:30:10 +0300 Subject: [PATCH 61/76] [doc][skip ci] Add docs for monolog handler. --- docs/index.md | 1 + docs/monolog/send-messages-to-mq.md | 60 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 docs/monolog/send-messages-to-mq.md diff --git a/docs/index.md b/docs/index.md index 474b25d2d..9f877b24e 100644 --- a/docs/index.md +++ b/docs/index.md @@ -45,6 +45,7 @@ * [Use cases](#use-cases) - [FOSElasticaBundle. Populate command optimizations](elastica-bundle/populate-command-optimization.md) - [Symfony. Async event dispatcher](async_event_dispatcher/quick_tour.md) + - [Monolog. Send messages to message queue](monolog/send-messages-to-mq.md) * [Development](#development) - [Contribution](contribution.md) diff --git a/docs/monolog/send-messages-to-mq.md b/docs/monolog/send-messages-to-mq.md new file mode 100644 index 000000000..caead3723 --- /dev/null +++ b/docs/monolog/send-messages-to-mq.md @@ -0,0 +1,60 @@ +# Enqueue Monolog Handlers + +The package provides handlers for [Monolog](https://github.com/Seldaek/monolog). +These handler allows to send logs to MQ using any [queue-interop](https://github.com/queue-interop/queue-interop) compatible transports. + +## Installation + +You have to install monolog itself, queue interop handlers and one of [the transports](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md#transports). +For the simplicity we are going to install the filesystem based MQ. + +``` +composer require enqueue/monolog-queue-handler monolog/monlog enqueue/fs +``` + +## Usage + +```php +createContext(); + +// create a log channel +$log = new Logger('name'); +$log->pushHandler(new QueueInteropHandler($context)); + +// add records to the log +$log->warning('Foo'); +$log->error('Bar'); +``` + +the consumer may look like this: + +```php +createContext(); + +$consumer = new QueueConsumer($context); +$consumer->bind('log', function(PsrMessage $message) { + echo $message->getBody().PHP_EOL; + + return PsrProcessor::ACK; +}); + +$consumer->consume(); + +``` + +[back to index](../index.md) \ No newline at end of file From c57a79098da055c2990737c1092704d8a1941239 Mon Sep 17 00:00:00 2001 From: Toni Rudolf Date: Mon, 7 Aug 2017 11:36:42 +0200 Subject: [PATCH 62/76] continue if exclusive is set to false --- .../Compiler/BuildExclusiveCommandsExtensionPass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/enqueue-bundle/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php b/pkg/enqueue-bundle/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php index f01468f0d..978341ab7 100644 --- a/pkg/enqueue-bundle/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php +++ b/pkg/enqueue-bundle/DependencyInjection/Compiler/BuildExclusiveCommandsExtensionPass.php @@ -32,7 +32,7 @@ public function process(ContainerBuilder $container) continue; } - if (false == isset($subscription['exclusive'])) { + if (false == isset($subscription['exclusive']) || $subscription['exclusive'] === false) { continue; } From 01bcb21666921b06d0ff7cf10d86ae1e505e15e3 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 13:56:16 +0300 Subject: [PATCH 63/76] delay strategy --- .../RabbitMQDelayPluginDelayStrategy.php | 7 +- pkg/amqp-tools/RabbitMQDlxDelayStrategy.php | 5 +- .../RabbitMqDelayPluginDelayStrategyTest.php | 217 ++++++++++++++++++ .../Tests/RabbitMqDlxDelayStrategyTest.php | 198 ++++++++++++++++ 4 files changed, 423 insertions(+), 4 deletions(-) create mode 100644 pkg/amqp-tools/Tests/RabbitMqDelayPluginDelayStrategyTest.php create mode 100644 pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php diff --git a/pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php b/pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php index 4ad3ec453..fc4103789 100644 --- a/pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php +++ b/pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php @@ -10,7 +10,7 @@ use Interop\Amqp\Impl\AmqpBind; use Interop\Queue\InvalidDestinationException; -class RabbitMQDelayPluginDelayStrategy implements DelayStrategy +class RabbitMqDelayPluginDelayStrategy implements DelayStrategy { /** * {@inheritdoc} @@ -47,7 +47,10 @@ public function delayMessage(AmqpContext $context, AmqpDestination $dest, AmqpMe } $producer = $context->createProducer(); - $producer->setDelayStrategy(null); + + if ($producer instanceof DelayStrategyAware) { + $producer->setDelayStrategy(null); + } $producer->send($delayTopic, $delayMessage); } diff --git a/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php b/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php index 9ca2ba506..6211885e3 100644 --- a/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php +++ b/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php @@ -9,7 +9,7 @@ use Interop\Amqp\AmqpTopic; use Interop\Queue\InvalidDestinationException; -class RabbitMQDlxDelayStrategy implements DelayStrategy +class RabbitMqDlxDelayStrategy implements DelayStrategy { /** * {@inheritdoc} @@ -24,7 +24,6 @@ public function delayMessage(AmqpContext $context, AmqpDestination $dest, AmqpMe unset($properties['x-death']); $delayMessage = $context->createMessage($message->getBody(), $properties, $message->getHeaders()); - $delayMessage->setExpiration((int) $delayMsec); $delayMessage->setRoutingKey($message->getRoutingKey()); if ($dest instanceof AmqpTopic) { @@ -33,11 +32,13 @@ public function delayMessage(AmqpContext $context, AmqpDestination $dest, AmqpMe $delayQueue = $context->createQueue($name); $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE); + $delayQueue->setArgument('x-message-ttl', $delayMsec); $delayQueue->setArgument('x-dead-letter-exchange', $dest->getTopicName()); $delayQueue->setArgument('x-dead-letter-routing-key', (string) $delayMessage->getRoutingKey()); } elseif ($dest instanceof AmqpQueue) { $delayQueue = $context->createQueue('enqueue.'.$dest->getQueueName().'.'.$delayMsec.'.delayed'); $delayQueue->addFlag(AmqpTopic::FLAG_DURABLE); + $delayQueue->setArgument('x-message-ttl', $delayMsec); $delayQueue->setArgument('x-dead-letter-exchange', ''); $delayQueue->setArgument('x-dead-letter-routing-key', $dest->getQueueName()); } else { diff --git a/pkg/amqp-tools/Tests/RabbitMqDelayPluginDelayStrategyTest.php b/pkg/amqp-tools/Tests/RabbitMqDelayPluginDelayStrategyTest.php new file mode 100644 index 000000000..9f19e59d5 --- /dev/null +++ b/pkg/amqp-tools/Tests/RabbitMqDelayPluginDelayStrategyTest.php @@ -0,0 +1,217 @@ +assertClassImplements(DelayStrategy::class, RabbitMqDelayPluginDelayStrategy::class); + } + + public function testShouldSendDelayedMessageToTopic() + { + $delayedTopic = new AmqpTopic('the-topic'); + $delayedMessage = new AmqpMessage(); + + $producer = $this->createProducerMock(); + $producer + ->expects($this->once()) + ->method('send') + ->with($this->identicalTo($delayedTopic), $this->identicalTo($delayedMessage)) + ; + + $context = $this->createContextMock(); + $context + ->expects($this->once()) + ->method('createTopic') + ->with($this->identicalTo('enqueue.the-topic.delayed')) + ->willReturn($delayedTopic) + ; + $context + ->expects($this->once()) + ->method('declareTopic') + ->with($this->identicalTo($delayedTopic)) + ; + $context + ->expects($this->once()) + ->method('createProducer') + ->willReturn($producer) + ; + $context + ->expects($this->once()) + ->method('createMessage') + ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue'])) + ->willReturn($delayedMessage) + ; + $context + ->expects($this->once()) + ->method('bind') + ->with($this->isInstanceOf(AmqpBind::class)) + ; + + $message = new AmqpMessage('the body', ['key' => 'value'], ['hkey' => 'hvalue']); + $message->setRoutingKey('the-routing-key'); + + $dest = new AmqpTopic('the-topic'); + $dest->setFlags(12345); + + $strategy = new RabbitMqDelayPluginDelayStrategy(); + $strategy->delayMessage($context, $dest, $message, 10000); + + $this->assertSame(12345, $delayedTopic->getFlags()); + $this->assertSame('x-delayed-message', $delayedTopic->getType()); + $this->assertSame([ + 'x-delayed-type' => 'direct', + ], $delayedTopic->getArguments()); + + $this->assertSame(['x-delay' => 10000], $delayedMessage->getProperties()); + $this->assertSame('the-routing-key', $delayedMessage->getRoutingKey()); + } + + public function testShouldSendDelayedMessageToQueue() + { + $delayedTopic = new AmqpTopic('the-topic'); + $delayedMessage = new AmqpMessage(); + + $producer = $this->createProducerMock(); + $producer + ->expects($this->once()) + ->method('send') + ->with($this->identicalTo($delayedTopic), $this->identicalTo($delayedMessage)) + ; + + $context = $this->createContextMock(); + $context + ->expects($this->once()) + ->method('createTopic') + ->with($this->identicalTo('enqueue.queue.delayed')) + ->willReturn($delayedTopic) + ; + $context + ->expects($this->once()) + ->method('declareTopic') + ->with($this->identicalTo($delayedTopic)) + ; + $context + ->expects($this->once()) + ->method('createProducer') + ->willReturn($producer) + ; + $context + ->expects($this->once()) + ->method('createMessage') + ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue'])) + ->willReturn($delayedMessage) + ; + $context + ->expects($this->once()) + ->method('bind') + ->with($this->isInstanceOf(AmqpBind::class)) + ; + + $message = new AmqpMessage('the body', ['key' => 'value'], ['hkey' => 'hvalue']); + $message->setRoutingKey('the-routing-key'); + + $dest = new AmqpQueue('the-queue'); + + $strategy = new RabbitMqDelayPluginDelayStrategy(); + $strategy->delayMessage($context, $dest, $message, 10000); + + $this->assertSame(AmqpQueue::FLAG_DURABLE, $delayedTopic->getFlags()); + $this->assertSame('x-delayed-message', $delayedTopic->getType()); + $this->assertSame([ + 'x-delayed-type' => 'direct', + ], $delayedTopic->getArguments()); + + $this->assertSame(['x-delay' => 10000], $delayedMessage->getProperties()); + $this->assertSame('the-queue', $delayedMessage->getRoutingKey()); + } + + public function testShouldThrowExceptionIfInvalidDestination() + { + $delayedMessage = new AmqpMessage(); + + $context = $this->createContextMock(); + $context + ->expects($this->once()) + ->method('createMessage') + ->willReturn($delayedMessage) + ; + + $strategy = new RabbitMqDelayPluginDelayStrategy(); + + $this->expectException(InvalidDestinationException::class); + $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpTopic|Interop\Amqp\AmqpQueue but got'); + + $strategy->delayMessage($context, $this->createMock(AmqpDestination::class), new AmqpMessage(), 10000); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext + */ + private function createContextMock() + { + return $this->createMock(AmqpContext::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|TestProducer + */ + private function createProducerMock() + { + return $this->createMock(TestProducer::class); + } +} + +class TestProducer implements AmqpProducer, DelayStrategy +{ + public function delayMessage(AmqpContext $context, AmqpDestination $dest, \Interop\Amqp\AmqpMessage $message, $delayMsec) + { + } + + public function send(PsrDestination $destination, PsrMessage $message) + { + } + + public function setDeliveryDelay($deliveryDelay) + { + } + + public function getDeliveryDelay() + { + } + + public function setPriority($priority) + { + } + + public function getPriority() + { + } + + public function setTimeToLive($timeToLive) + { + } + + public function getTimeToLive() + { + } +} diff --git a/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php b/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php new file mode 100644 index 000000000..13e820ffb --- /dev/null +++ b/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php @@ -0,0 +1,198 @@ +assertClassImplements(DelayStrategy::class, RabbitMqDlxDelayStrategy::class); + } + + public function testShouldSendDelayedMessageToTopic() + { + $delayedQueue = new AmqpQueue('the-queue'); + $delayedMessage = new AmqpMessage(); + + $producer = $this->createProducerMock(); + $producer + ->expects($this->once()) + ->method('send') + ->with($this->identicalTo($delayedQueue), $this->identicalTo($delayedMessage)) + ; + + $context = $this->createContextMock(); + $context + ->expects($this->once()) + ->method('createQueue') + ->with($this->identicalTo('enqueue.the-topic.the-routing-key.10000.x.delay')) + ->willReturn($delayedQueue) + ; + $context + ->expects($this->once()) + ->method('declareQueue') + ->with($this->identicalTo($delayedQueue)) + ; + $context + ->expects($this->once()) + ->method('createProducer') + ->willReturn($producer) + ; + $context + ->expects($this->once()) + ->method('createMessage') + ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue'])) + ->willReturn($delayedMessage) + ; + + $message = new AmqpMessage('the body', ['key' => 'value'], ['hkey' => 'hvalue']); + $message->setRoutingKey('the-routing-key'); + + $dest = new AmqpTopic('the-topic'); + + $strategy = new RabbitMqDlxDelayStrategy(); + $strategy->delayMessage($context, $dest, $message, 10000); + + $this->assertSame(AmqpQueue::FLAG_DURABLE, $delayedQueue->getFlags()); + $this->assertSame([ + 'x-message-ttl' => 10000, + 'x-dead-letter-exchange' => 'the-topic', + 'x-dead-letter-routing-key' => 'the-routing-key', + ], $delayedQueue->getArguments()); + } + + public function testShouldSendDelayedMessageToQueue() + { + $delayedQueue = new AmqpQueue('the-queue'); + $delayedMessage = new AmqpMessage(); + + $producer = $this->createProducerMock(); + $producer + ->expects($this->once()) + ->method('send') + ->with($this->identicalTo($delayedQueue), $this->identicalTo($delayedMessage)) + ; + + $context = $this->createContextMock(); + $context + ->expects($this->once()) + ->method('createQueue') + ->with($this->identicalTo('enqueue.the-queue.10000.delayed')) + ->willReturn($delayedQueue) + ; + $context + ->expects($this->once()) + ->method('declareQueue') + ->with($this->identicalTo($delayedQueue)) + ; + $context + ->expects($this->once()) + ->method('createProducer') + ->willReturn($producer) + ; + $context + ->expects($this->once()) + ->method('createMessage') + ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue'])) + ->willReturn($delayedMessage) + ; + + $message = new AmqpMessage('the body', ['key' => 'value'], ['hkey' => 'hvalue']); + $message->setRoutingKey('the-routing-key'); + + $dest = new AmqpQueue('the-queue'); + + $strategy = new RabbitMqDlxDelayStrategy(); + $strategy->delayMessage($context, $dest, $message, 10000); + + $this->assertSame(AmqpQueue::FLAG_DURABLE, $delayedQueue->getFlags()); + $this->assertSame([ + 'x-message-ttl' => 10000, + 'x-dead-letter-exchange' => '', + 'x-dead-letter-routing-key' => 'the-queue', + ], $delayedQueue->getArguments()); + } + + public function testShouldUnsetXDeathProperty() + { + $delayedQueue = new AmqpQueue('the-queue'); + $delayedMessage = new AmqpMessage(); + + $producer = $this->createProducerMock(); + + $context = $this->createContextMock(); + $context + ->expects($this->once()) + ->method('createQueue') + ->with($this->identicalTo('enqueue.the-queue.10000.delayed')) + ->willReturn($delayedQueue) + ; + $context + ->expects($this->once()) + ->method('createProducer') + ->willReturn($producer) + ; + $context + ->expects($this->once()) + ->method('createMessage') + ->with($this->identicalTo('the body'), $this->identicalTo(['key' => 'value']), $this->identicalTo(['hkey' => 'hvalue'])) + ->willReturn($delayedMessage) + ; + + $message = new AmqpMessage('the body', ['key' => 'value', 'x-death' => 'value'], ['hkey' => 'hvalue']); + + $dest = new AmqpQueue('the-queue'); + + $strategy = new RabbitMqDlxDelayStrategy(); + $strategy->delayMessage($context, $dest, $message, 10000); + } + + public function testShouldThrowExceptionIfInvalidDestination() + { + $delayedMessage = new AmqpMessage(); + + $context = $this->createContextMock(); + $context + ->expects($this->once()) + ->method('createMessage') + ->willReturn($delayedMessage) + ; + + $strategy = new RabbitMqDlxDelayStrategy(); + + $this->expectException(InvalidDestinationException::class); + $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpTopic|Interop\Amqp\AmqpQueue but got'); + + $strategy->delayMessage($context, $this->createMock(AmqpDestination::class), new AmqpMessage(), 10000); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext + */ + private function createContextMock() + { + return $this->createMock(AmqpContext::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|AmqpProducer + */ + private function createProducerMock() + { + return $this->createMock(AmqpProducer::class); + } +} From ea49ff5389a3fd1b7dc2965d141be947cefbcc69 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 14:40:55 +0300 Subject: [PATCH 64/76] delay strategy --- pkg/amqp-bunny/AmqpConnectionFactory.php | 16 ++++- pkg/amqp-bunny/AmqpContext.php | 11 +++- pkg/amqp-bunny/AmqpProducer.php | 37 ++++++++--- pkg/amqp-bunny/Tests/AmqpProducerTest.php | 77 ++++++++++++++++++++--- 4 files changed, 118 insertions(+), 23 deletions(-) diff --git a/pkg/amqp-bunny/AmqpConnectionFactory.php b/pkg/amqp-bunny/AmqpConnectionFactory.php index cb73b8ae4..422650d80 100644 --- a/pkg/amqp-bunny/AmqpConnectionFactory.php +++ b/pkg/amqp-bunny/AmqpConnectionFactory.php @@ -3,10 +3,14 @@ namespace Enqueue\AmqpBunny; use Bunny\Client; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpConnectionFactory as InteropAmqpConnectionFactory; -class AmqpConnectionFactory implements InteropAmqpConnectionFactory +class AmqpConnectionFactory implements InteropAmqpConnectionFactory, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var array */ @@ -72,12 +76,18 @@ public function __construct($config = 'amqp://') public function createContext() { if ($this->config['lazy']) { - return new AmqpContext(function () { + $context = new AmqpContext(function () { return $this->establishConnection()->channel(); }, $this->config); + $context->setDelayStrategy($this->delayStrategy); + + return $context; } - return new AmqpContext($this->establishConnection()->channel(), $this->config); + $context = new AmqpContext($this->establishConnection()->channel(), $this->config); + $context->setDelayStrategy($this->delayStrategy); + + return $context; } /** diff --git a/pkg/amqp-bunny/AmqpContext.php b/pkg/amqp-bunny/AmqpContext.php index 7a596dd61..3638434a4 100644 --- a/pkg/amqp-bunny/AmqpContext.php +++ b/pkg/amqp-bunny/AmqpContext.php @@ -3,6 +3,8 @@ namespace Enqueue\AmqpBunny; use Bunny\Channel; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpBind as InteropAmqpBind; use Interop\Amqp\AmqpContext as InteropAmqpContext; use Interop\Amqp\AmqpMessage as InteropAmqpMessage; @@ -17,8 +19,10 @@ use Interop\Queue\PsrDestination; use Interop\Queue\PsrTopic; -class AmqpContext implements InteropAmqpContext +class AmqpContext implements InteropAmqpContext, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var Channel */ @@ -124,7 +128,10 @@ public function createConsumer(PsrDestination $destination) */ public function createProducer() { - return new AmqpProducer($this->getBunnyChannel()); + $producer = new AmqpProducer($this->getBunnyChannel(), $this); + $producer->setDelayStrategy($this->delayStrategy); + + return $producer; } /** diff --git a/pkg/amqp-bunny/AmqpProducer.php b/pkg/amqp-bunny/AmqpProducer.php index 9d701bbe2..282fdcbd7 100644 --- a/pkg/amqp-bunny/AmqpProducer.php +++ b/pkg/amqp-bunny/AmqpProducer.php @@ -3,6 +3,8 @@ namespace Enqueue\AmqpBunny; use Bunny\Channel; +use Enqueue\AmqpTools\DelayStrategyAware; +use Enqueue\AmqpTools\DelayStrategyAwareTrait; use Interop\Amqp\AmqpMessage as InteropAmqpMessage; use Interop\Amqp\AmqpProducer as InteropAmqpProducer; use Interop\Amqp\AmqpQueue as InteropAmqpQueue; @@ -14,8 +16,10 @@ use Interop\Queue\PsrMessage; use Interop\Queue\PsrTopic; -class AmqpProducer implements InteropAmqpProducer +class AmqpProducer implements InteropAmqpProducer, DelayStrategyAware { + use DelayStrategyAwareTrait; + /** * @var int|null */ @@ -32,11 +36,23 @@ class AmqpProducer implements InteropAmqpProducer private $channel; /** - * @param Channel $channel + * @var int + */ + private $deliveryDelay; + + /** + * @var AmqpContext + */ + private $context; + + /** + * @param Channel $channel + * @param AmqpContext $context */ - public function __construct(Channel $channel) + public function __construct(Channel $channel, AmqpContext $context) { $this->channel = $channel; + $this->context = $context; } /** @@ -47,8 +63,7 @@ public function send(PsrDestination $destination, PsrMessage $message) { $destination instanceof PsrTopic ? InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpTopic::class) - : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class) - ; + : InvalidDestinationException::assertDestinationInstanceOf($destination, InteropAmqpQueue::class); InvalidMessageException::assertMessageInstanceOf($message, InteropAmqpMessage::class); @@ -66,7 +81,9 @@ public function send(PsrDestination $destination, PsrMessage $message) $amqpProperties['application_headers'] = $appProperties; } - if ($destination instanceof InteropAmqpTopic) { + if ($this->deliveryDelay) { + $this->delayStrategy->delayMessage($this->context, $destination, $message, $this->deliveryDelay); + } elseif ($destination instanceof InteropAmqpTopic) { $this->channel->publish( $message->getBody(), $amqpProperties, @@ -92,11 +109,11 @@ public function send(PsrDestination $destination, PsrMessage $message) */ public function setDeliveryDelay($deliveryDelay) { - if (null === $deliveryDelay) { - return; + if (null === $this->delayStrategy) { + throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); } - throw DeliveryDelayNotSupportedException::providerDoestNotSupportIt(); + $this->deliveryDelay = $deliveryDelay; } /** @@ -104,7 +121,7 @@ public function setDeliveryDelay($deliveryDelay) */ public function getDeliveryDelay() { - return null; + return $this->deliveryDelay; } /** diff --git a/pkg/amqp-bunny/Tests/AmqpProducerTest.php b/pkg/amqp-bunny/Tests/AmqpProducerTest.php index 91a029684..ddb067858 100644 --- a/pkg/amqp-bunny/Tests/AmqpProducerTest.php +++ b/pkg/amqp-bunny/Tests/AmqpProducerTest.php @@ -4,12 +4,15 @@ use Bunny\Channel; use Bunny\Message; +use Enqueue\AmqpBunny\AmqpContext; use Enqueue\AmqpBunny\AmqpProducer; +use Enqueue\AmqpTools\DelayStrategy; use Enqueue\Test\ClassExtensionTrait; use Interop\Amqp\AmqpMessage as InteropAmqpMessage; use Interop\Amqp\Impl\AmqpMessage; use Interop\Amqp\Impl\AmqpQueue; use Interop\Amqp\Impl\AmqpTopic; +use Interop\Queue\DeliveryDelayNotSupportedException; use Interop\Queue\InvalidDestinationException; use Interop\Queue\InvalidMessageException; use Interop\Queue\PsrDestination; @@ -23,7 +26,7 @@ class AmqpProducerTest extends TestCase public function testCouldBeConstructedWithRequiredArguments() { - new AmqpProducer($this->createBunnyChannelMock()); + new AmqpProducer($this->createBunnyChannelMock(), $this->createContextMock()); } public function testShouldImplementPsrProducerInterface() @@ -33,7 +36,7 @@ public function testShouldImplementPsrProducerInterface() public function testShouldThrowExceptionWhenDestinationTypeIsInvalid() { - $producer = new AmqpProducer($this->createBunnyChannelMock()); + $producer = new AmqpProducer($this->createBunnyChannelMock(), $this->createContextMock()); $this->expectException(InvalidDestinationException::class); $this->expectExceptionMessage('The destination must be an instance of Interop\Amqp\AmqpQueue but got'); @@ -43,7 +46,7 @@ public function testShouldThrowExceptionWhenDestinationTypeIsInvalid() public function testShouldThrowExceptionWhenMessageTypeIsInvalid() { - $producer = new AmqpProducer($this->createBunnyChannelMock()); + $producer = new AmqpProducer($this->createBunnyChannelMock(), $this->createContextMock()); $this->expectException(InvalidMessageException::class); $this->expectExceptionMessage('The message must be an instance of Interop\Amqp\AmqpMessage but it is'); @@ -65,7 +68,7 @@ public function testShouldPublishMessageToTopic() $message = new AmqpMessage('body'); $message->setRoutingKey('routing-key'); - $producer = new AmqpProducer($channel); + $producer = new AmqpProducer($channel, $this->createContextMock()); $producer->send($topic, $message); } @@ -80,10 +83,52 @@ public function testShouldPublishMessageToQueue() $queue = new AmqpQueue('queue'); - $producer = new AmqpProducer($channel); + $producer = new AmqpProducer($channel, $this->createContextMock()); $producer->send($queue, new AmqpMessage('body')); } + public function testShouldDelayMessage() + { + $channel = $this->createBunnyChannelMock(); + $channel + ->expects($this->never()) + ->method('publish') + ; + + $message = new AmqpMessage('body'); + $context = $this->createContextMock(); + $queue = new AmqpQueue('queue'); + + $delayStrategy = $this->createDelayStrategyMock(); + $delayStrategy + ->expects($this->once()) + ->method('delayMessage') + ->with($this->identicalTo($context), $this->identicalTo($queue), $this->identicalTo($message), 10000) + ; + + $producer = new AmqpProducer($channel, $context); + $producer->setDelayStrategy($delayStrategy); + $producer->setDeliveryDelay(10000); + + $producer->send($queue, $message); + } + + public function testShouldThrowExceptionOnSetDeliveryDelayWhenDeliveryStrategyIsNotSet() + { + $channel = $this->createBunnyChannelMock(); + $channel + ->expects($this->never()) + ->method('publish') + ; + + $producer = new AmqpProducer($channel, $this->createContextMock()); + + $this->expectException(DeliveryDelayNotSupportedException::class); + $this->expectExceptionMessage('The provider does not support delivery delay feature'); + + $producer->setDeliveryDelay(10000); + } + public function testShouldSetMessageHeaders() { $channel = $this->createBunnyChannelMock(); @@ -93,7 +138,7 @@ public function testShouldSetMessageHeaders() ->with($this->anything(), ['content_type' => 'text/plain']) ; - $producer = new AmqpProducer($channel); + $producer = new AmqpProducer($channel, $this->createContextMock()); $producer->send(new AmqpTopic('name'), new AmqpMessage('body', [], ['content_type' => 'text/plain'])); } @@ -106,7 +151,7 @@ public function testShouldSetMessageProperties() ->with($this->anything(), ['application_headers' => ['key' => 'value']]) ; - $producer = new AmqpProducer($channel); + $producer = new AmqpProducer($channel, $this->createContextMock()); $producer->send(new AmqpTopic('name'), new AmqpMessage('body', ['key' => 'value'])); } @@ -123,7 +168,7 @@ public function testShouldPropagateFlags() $message->addFlag(InteropAmqpMessage::FLAG_IMMEDIATE); $message->addFlag(InteropAmqpMessage::FLAG_MANDATORY); - $producer = new AmqpProducer($channel); + $producer = new AmqpProducer($channel, $this->createContextMock()); $producer->send(new AmqpTopic('name'), $message); } @@ -150,4 +195,20 @@ private function createBunnyChannelMock() { return $this->createMock(Channel::class); } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|AmqpContext + */ + private function createContextMock() + { + return $this->createMock(AmqpContext::class); + } + + /** + * @return \PHPUnit_Framework_MockObject_MockObject|DelayStrategy + */ + private function createDelayStrategyMock() + { + return $this->createMock(DelayStrategy::class); + } } From df2dd22c31fcf817c422d32a6ee2141d15154cee Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 7 Aug 2017 14:41:29 +0300 Subject: [PATCH 65/76] Update index.md --- docs/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.md b/docs/index.md index 9f877b24e..2c1243b87 100644 --- a/docs/index.md +++ b/docs/index.md @@ -59,3 +59,4 @@ * [FOSElasticaBundle. Improve performance of fos:elastica:populate command](https://github.com/php-enqueue/enqueue-elastica-bundle) * [Message bus to every PHP application](https://blog.forma-pro.com/message-bus-to-every-php-application-42a7d3fbb30b) * [Symfony Async EventDispatcher](https://blog.forma-pro.com/symfony-async-eventdispatcher-d01055a255cf) +* [Spool Swiftmailer emails to real message queue.](https://blog.forma-pro.com/spool-swiftmailer-emails-to-real-message-queue-9ecb8b53b5de) From 5ae3d14827294c7662e7f51ee5cc6607354cc71f Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 15:10:50 +0300 Subject: [PATCH 66/76] delay strategy --- ...ayedMessageWithDelayPluginStrategyTest.php | 34 +++++++++++++++++++ ...ceiveDelayedMessageWithDlxStrategyTest.php | 34 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php create mode 100644 pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php diff --git a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php new file mode 100644 index 000000000..3ee989c14 --- /dev/null +++ b/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -0,0 +1,34 @@ +setDelayStrategy(new RabbitMqDlxDelayStrategy()); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = parent::createQueue($context, $queueName); + + $context->declareQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php new file mode 100644 index 000000000..c77af7969 --- /dev/null +++ b/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php @@ -0,0 +1,34 @@ +setDelayStrategy(new RabbitMqDlxDelayStrategy()); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = parent::createQueue($context, $queueName); + + $context->declareQueue($queue); + + return $queue; + } +} From c9b7822a1c58fa1ac5b647ef5b07b060134d5a0c Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 15:21:03 +0300 Subject: [PATCH 67/76] delay strategy --- ...ayedMessageWithDelayPluginStrategyTest.php | 34 +++++++++++++++++++ ...ceiveDelayedMessageWithDlxStrategyTest.php | 34 +++++++++++++++++++ ...ayedMessageWithDelayPluginStrategyTest.php | 34 +++++++++++++++++++ ...ceiveDelayedMessageWithDlxStrategyTest.php | 34 +++++++++++++++++++ ...ayedMessageWithDelayPluginStrategyTest.php | 4 +-- 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php create mode 100644 pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php create mode 100644 pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php create mode 100644 pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php diff --git a/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php new file mode 100644 index 000000000..c21a0d82f --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -0,0 +1,34 @@ +setDelayStrategy(new RabbitMQDelayPluginDelayStrategy()); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = parent::createQueue($context, $queueName); + + $context->declareQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php new file mode 100644 index 000000000..a0e9c41b1 --- /dev/null +++ b/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php @@ -0,0 +1,34 @@ +setDelayStrategy(new RabbitMqDlxDelayStrategy()); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = parent::createQueue($context, $queueName); + + $context->declareQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php new file mode 100644 index 000000000..0017dec54 --- /dev/null +++ b/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -0,0 +1,34 @@ +setDelayStrategy(new RabbitMQDelayPluginDelayStrategy()); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = parent::createQueue($context, $queueName); + + $context->declareQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php new file mode 100644 index 000000000..038acd133 --- /dev/null +++ b/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php @@ -0,0 +1,34 @@ +setDelayStrategy(new RabbitMqDlxDelayStrategy()); + + return $factory->createContext(); + } + + /** + * {@inheritdoc} + */ + protected function createQueue(PsrContext $context, $queueName) + { + $queue = parent::createQueue($context, $queueName); + + $context->declareQueue($queue); + + return $queue; + } +} diff --git a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php index 3ee989c14..a9ca83d60 100644 --- a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php +++ b/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -3,7 +3,7 @@ namespace Enqueue\AmqpLib\Tests\Spec; use Enqueue\AmqpLib\AmqpConnectionFactory; -use Enqueue\AmqpTools\RabbitMqDlxDelayStrategy; +use Enqueue\AmqpTools\RabbitMQDelayPluginDelayStrategy; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; @@ -15,7 +15,7 @@ class SendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndRec protected function createContext() { $factory = new AmqpConnectionFactory(getenv('AMQP_DSN')); - $factory->setDelayStrategy(new RabbitMqDlxDelayStrategy()); + $factory->setDelayStrategy(new RabbitMQDelayPluginDelayStrategy()); return $factory->createContext(); } From 6b99d3a84007d87762a509acadbad6c399ab3dca Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 15:28:15 +0300 Subject: [PATCH 68/76] delay strategy --- pkg/amqp-bunny/composer.json | 1 + pkg/amqp-ext/composer.json | 1 + pkg/amqp-lib/composer.json | 1 + 3 files changed, 3 insertions(+) diff --git a/pkg/amqp-bunny/composer.json b/pkg/amqp-bunny/composer.json index 130660212..109dedd00 100644 --- a/pkg/amqp-bunny/composer.json +++ b/pkg/amqp-bunny/composer.json @@ -15,6 +15,7 @@ "queue-interop/amqp-interop": "^0.6@dev", "bunny/bunny": "^0.2.4", + "enqueue/amqp-tools": "^0.7@dev", "psr/log": "^1" }, "require-dev": { diff --git a/pkg/amqp-ext/composer.json b/pkg/amqp-ext/composer.json index 5329c708d..6b69dddcf 100644 --- a/pkg/amqp-ext/composer.json +++ b/pkg/amqp-ext/composer.json @@ -15,6 +15,7 @@ "ext-amqp": "^1.6", "queue-interop/amqp-interop": "^0.6@dev", + "enqueue/amqp-tools": "^0.7@dev", "psr/log": "^1" }, "require-dev": { diff --git a/pkg/amqp-lib/composer.json b/pkg/amqp-lib/composer.json index 1241cc233..efb9a200e 100644 --- a/pkg/amqp-lib/composer.json +++ b/pkg/amqp-lib/composer.json @@ -15,6 +15,7 @@ "php-amqplib/php-amqplib": "^2.7@dev", "queue-interop/queue-interop": "^0.6@dev", "queue-interop/amqp-interop": "^0.6@dev", + "enqueue/amqp-tools": "^0.7@dev", "psr/log": "^1" }, "require-dev": { From 073432d42235e004e614d0c5fd4df62997690308 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 15:36:07 +0300 Subject: [PATCH 69/76] delay strategy --- ...luginDelayStrategy.php => RabbitMqDelayPluginDelayStrategy.ph} | 0 ...{RabbitMQDlxDelayStrategy.php => RabbitMqDlxDelayStrategy.php} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename pkg/amqp-tools/{RabbitMQDelayPluginDelayStrategy.php => RabbitMqDelayPluginDelayStrategy.ph} (100%) rename pkg/amqp-tools/{RabbitMQDlxDelayStrategy.php => RabbitMqDlxDelayStrategy.php} (100%) diff --git a/pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php b/pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.ph similarity index 100% rename from pkg/amqp-tools/RabbitMQDelayPluginDelayStrategy.php rename to pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.ph diff --git a/pkg/amqp-tools/RabbitMQDlxDelayStrategy.php b/pkg/amqp-tools/RabbitMqDlxDelayStrategy.php similarity index 100% rename from pkg/amqp-tools/RabbitMQDlxDelayStrategy.php rename to pkg/amqp-tools/RabbitMqDlxDelayStrategy.php From e23a39c6a907b28d63524b35f915e0e18acb2d55 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 15:47:17 +0300 Subject: [PATCH 70/76] delay strategy --- ...endAndReceiveDelayedMessageWithDelayPluginStrategyTest.php | 4 ++-- ...endAndReceiveDelayedMessageWithDelayPluginStrategyTest.php | 4 ++-- ...endAndReceiveDelayedMessageWithDelayPluginStrategyTest.php | 4 ++-- ...nDelayStrategy.ph => RabbitMqDelayPluginDelayStrategy.php} | 0 4 files changed, 6 insertions(+), 6 deletions(-) rename pkg/amqp-tools/{RabbitMqDelayPluginDelayStrategy.ph => RabbitMqDelayPluginDelayStrategy.php} (100%) diff --git a/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php index c21a0d82f..14dec4fb4 100644 --- a/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php +++ b/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -3,7 +3,7 @@ namespace Enqueue\AmqpBunny\Tests\Spec; use Enqueue\AmqpLib\AmqpConnectionFactory; -use Enqueue\AmqpTools\RabbitMQDelayPluginDelayStrategy; +use Enqueue\AmqpTools\RabbitMqDelayPluginDelayStrategy; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; @@ -15,7 +15,7 @@ class SendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndRec protected function createContext() { $factory = new AmqpConnectionFactory(getenv('AMQP_DSN')); - $factory->setDelayStrategy(new RabbitMQDelayPluginDelayStrategy()); + $factory->setDelayStrategy(new RabbitMqDelayPluginDelayStrategy()); return $factory->createContext(); } diff --git a/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php index 0017dec54..03a64266a 100644 --- a/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php +++ b/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -3,7 +3,7 @@ namespace Enqueue\AmqpExt\Tests\Spec; use Enqueue\AmqpLib\AmqpConnectionFactory; -use Enqueue\AmqpTools\RabbitMQDelayPluginDelayStrategy; +use Enqueue\AmqpTools\RabbitMqDelayPluginDelayStrategy; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; @@ -15,7 +15,7 @@ class SendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndRec protected function createContext() { $factory = new AmqpConnectionFactory(getenv('AMQP_DSN')); - $factory->setDelayStrategy(new RabbitMQDelayPluginDelayStrategy()); + $factory->setDelayStrategy(new RabbitMqDelayPluginDelayStrategy()); return $factory->createContext(); } diff --git a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php index a9ca83d60..4bffba112 100644 --- a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php +++ b/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -3,7 +3,7 @@ namespace Enqueue\AmqpLib\Tests\Spec; use Enqueue\AmqpLib\AmqpConnectionFactory; -use Enqueue\AmqpTools\RabbitMQDelayPluginDelayStrategy; +use Enqueue\AmqpTools\RabbitMqDelayPluginDelayStrategy; use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; @@ -15,7 +15,7 @@ class SendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndRec protected function createContext() { $factory = new AmqpConnectionFactory(getenv('AMQP_DSN')); - $factory->setDelayStrategy(new RabbitMQDelayPluginDelayStrategy()); + $factory->setDelayStrategy(new RabbitMqDelayPluginDelayStrategy()); return $factory->createContext(); } diff --git a/pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.ph b/pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.php similarity index 100% rename from pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.ph rename to pkg/amqp-tools/RabbitMqDelayPluginDelayStrategy.php From b2c5d7289fa15e1e98065f72472efd885c5ba3bd Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 15:53:21 +0300 Subject: [PATCH 71/76] delay strategy --- ...dAndReceiveDelayedMessageWithDelayPluginStrategyTest.php} | 5 ++++- ... AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php} | 5 ++++- ...dAndReceiveDelayedMessageWithDelayPluginStrategyTest.php} | 5 ++++- ... AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php} | 5 ++++- ...dAndReceiveDelayedMessageWithDelayPluginStrategyTest.php} | 5 ++++- ... AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php} | 5 ++++- 6 files changed, 24 insertions(+), 6 deletions(-) rename pkg/amqp-bunny/Tests/Spec/{SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php => AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php} (84%) rename pkg/amqp-bunny/Tests/Spec/{SendAndReceiveDelayedMessageWithDlxStrategyTest.php => AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php} (84%) rename pkg/amqp-ext/Tests/Spec/{SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php => AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php} (84%) rename pkg/amqp-ext/Tests/Spec/{SendAndReceiveDelayedMessageWithDlxStrategyTest.php => AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php} (84%) rename pkg/amqp-lib/Tests/Spec/{SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php => AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php} (84%) rename pkg/amqp-lib/Tests/Spec/{SendAndReceiveDelayedMessageWithDlxStrategyTest.php => AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php} (84%) diff --git a/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php similarity index 84% rename from pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php rename to pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php index 14dec4fb4..c5d7ed40b 100644 --- a/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -7,7 +7,10 @@ use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; -class SendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec +/** + * @group functional + */ +class AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec { /** * {@inheritdoc} diff --git a/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php similarity index 84% rename from pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php rename to pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php index a0e9c41b1..7795d01b8 100644 --- a/pkg/amqp-bunny/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php +++ b/pkg/amqp-bunny/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php @@ -7,7 +7,10 @@ use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; -class SendAndReceiveDelayedMessageWithDlxStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec +/** + * @group functional + */ +class AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec { /** * {@inheritdoc} diff --git a/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php similarity index 84% rename from pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php rename to pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php index 03a64266a..bb1b0c183 100644 --- a/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -7,7 +7,10 @@ use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; -class SendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec +/** + * @group functional + */ +class AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec { /** * {@inheritdoc} diff --git a/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php similarity index 84% rename from pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php rename to pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php index 038acd133..74d6233f1 100644 --- a/pkg/amqp-ext/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php +++ b/pkg/amqp-ext/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php @@ -7,7 +7,10 @@ use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; -class SendAndReceiveDelayedMessageWithDlxStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec +/** + * @group functional + */ +class AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec { /** * {@inheritdoc} diff --git a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php similarity index 84% rename from pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php rename to pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php index 4bffba112..12f93a4f1 100644 --- a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest.php @@ -7,7 +7,10 @@ use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; -class SendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec +/** + * @group functional + */ +class AmqpSendAndReceiveDelayedMessageWithDelayPluginStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec { /** * {@inheritdoc} diff --git a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php similarity index 84% rename from pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php rename to pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php index c77af7969..ca2284443 100644 --- a/pkg/amqp-lib/Tests/Spec/SendAndReceiveDelayedMessageWithDlxStrategyTest.php +++ b/pkg/amqp-lib/Tests/Spec/AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest.php @@ -7,7 +7,10 @@ use Interop\Queue\PsrContext; use Interop\Queue\Spec\SendAndReceiveDelayedMessageFromQueueSpec; -class SendAndReceiveDelayedMessageWithDlxStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec +/** + * @group functional + */ +class AmqpSendAndReceiveDelayedMessageWithDlxStrategyTest extends SendAndReceiveDelayedMessageFromQueueSpec { /** * {@inheritdoc} From a79764811fefcdc2969436bf24e8f65f4c8c3ec1 Mon Sep 17 00:00:00 2001 From: Alexander Kozienko Date: Mon, 7 Aug 2017 15:54:50 +0300 Subject: [PATCH 72/76] delay strategy --- pkg/amqp-bunny/AmqpContext.php | 2 +- pkg/amqp-ext/AmqpConnectionFactory.php | 2 +- pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/amqp-bunny/AmqpContext.php b/pkg/amqp-bunny/AmqpContext.php index 3638434a4..84508e856 100644 --- a/pkg/amqp-bunny/AmqpContext.php +++ b/pkg/amqp-bunny/AmqpContext.php @@ -128,7 +128,7 @@ public function createConsumer(PsrDestination $destination) */ public function createProducer() { - $producer = new AmqpProducer($this->getBunnyChannel(), $this); + $producer = new AmqpProducer($this->getBunnyChannel(), $this); $producer->setDelayStrategy($this->delayStrategy); return $producer; diff --git a/pkg/amqp-ext/AmqpConnectionFactory.php b/pkg/amqp-ext/AmqpConnectionFactory.php index c9c8131d3..ebf4d40df 100644 --- a/pkg/amqp-ext/AmqpConnectionFactory.php +++ b/pkg/amqp-ext/AmqpConnectionFactory.php @@ -87,7 +87,7 @@ public function __construct($config = 'amqp://') public function createContext() { if ($this->config['lazy']) { - $context = new AmqpContext(function () { + $context = new AmqpContext(function () { return $this->createExtContext($this->establishConnection()); }, $this->config['receive_method']); $context->setDelayStrategy($this->delayStrategy); diff --git a/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php b/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php index 13e820ffb..9531fe4ce 100644 --- a/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php +++ b/pkg/amqp-tools/Tests/RabbitMqDlxDelayStrategyTest.php @@ -5,8 +5,8 @@ use Enqueue\AmqpTools\DelayStrategy; use Enqueue\AmqpTools\RabbitMqDlxDelayStrategy; use Enqueue\Test\ClassExtensionTrait; -use Interop\Amqp\AmqpDestination; use Interop\Amqp\AmqpContext; +use Interop\Amqp\AmqpDestination; use Interop\Amqp\AmqpProducer; use Interop\Amqp\Impl\AmqpMessage; use Interop\Amqp\Impl\AmqpQueue; From 3cca41b41acc0850986ce19e8486ede5ed163921 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 7 Aug 2017 16:16:46 +0300 Subject: [PATCH 73/76] add amqp-tools to release scripts. --- bin/release | 2 +- bin/subtree-split | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/release b/bin/release index de8de6018..0cff197d6 100755 --- a/bin/release +++ b/bin/release @@ -14,7 +14,7 @@ fi CURRENT_BRANCH=`git rev-parse --abbrev-ref HEAD` -for REMOTE in origin stomp amqp-ext amqp-lib amqp-bunny pheanstalk gearman sqs fs redis dbal null rdkafka enqueue simple-client enqueue-bundle job-queue test async-event-dispatcher +for REMOTE in origin stomp amqp-ext amqp-lib amqp-bunny amqp-tools pheanstalk gearman sqs fs redis dbal null rdkafka enqueue simple-client enqueue-bundle job-queue test async-event-dispatcher do echo "" echo "" diff --git a/bin/subtree-split b/bin/subtree-split index 24dfb4768..ece707c24 100755 --- a/bin/subtree-split +++ b/bin/subtree-split @@ -49,6 +49,7 @@ remote stomp git@github.com:php-enqueue/stomp.git remote amqp-ext git@github.com:php-enqueue/amqp-ext.git remote amqp-lib git@github.com:php-enqueue/amqp-lib.git remote amqp-bunny git@github.com:php-enqueue/amqp-bunny.git +remote amqp-tools git@github.com:php-enqueue/amqp-tools.git remote pheanstalk git@github.com:php-enqueue/pheanstalk.git remote gearman git@github.com:php-enqueue/gearman.git remote fs git@github.com:php-enqueue/fs.git @@ -68,6 +69,7 @@ split 'pkg/stomp' stomp split 'pkg/amqp-ext' amqp-ext split 'pkg/amqp-lib' amqp-lib split 'pkg/amqp-bunny' amqp-bunny +split 'pkg/amqp-tools' amqp-tools split 'pkg/pheanstalk' pheanstalk split 'pkg/gearman' gearman split 'pkg/rdkafka' rdkafka From 9b543159f2852d6aedaf595a6d77142955fb0b43 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 7 Aug 2017 16:16:58 +0300 Subject: [PATCH 74/76] add license and readme to amqp tools --- pkg/amqp-tools/LICENSE | 20 ++++++++++++++++++++ pkg/amqp-tools/README.md | 27 +++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 pkg/amqp-tools/LICENSE create mode 100644 pkg/amqp-tools/README.md diff --git a/pkg/amqp-tools/LICENSE b/pkg/amqp-tools/LICENSE new file mode 100644 index 000000000..d9736f8bf --- /dev/null +++ b/pkg/amqp-tools/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) +Copyright (c) 2017 Kotliar Maksym + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/pkg/amqp-tools/README.md b/pkg/amqp-tools/README.md new file mode 100644 index 000000000..787df3aaa --- /dev/null +++ b/pkg/amqp-tools/README.md @@ -0,0 +1,27 @@ +# AMQP tools + +[![Gitter](https://badges.gitter.im/php-enqueue/Lobby.svg)](https://gitter.im/php-enqueue/Lobby) +[![Build Status](https://travis-ci.org/php-enqueue/amqp-tools.png?branch=master)](https://travis-ci.org/php-enqueue/amqp-tools) +[![Total Downloads](https://poser.pugx.org/enqueue/amqp-tools/d/total.png)](https://packagist.org/packages/enqueue/amqp-tools) +[![Latest Stable Version](https://poser.pugx.org/enqueue/amqp-tools/version.png)](https://packagist.org/packages/enqueue/amqp-tools) + +Provides features that are not part of the AMQP spec but could be built on top of. +The tools could be used with any [amqp interop](https://github.com/queue-interop/queue-interop#amqp-interop) compatible transport. + +## Resources + +* [Documentation](https://github.com/php-enqueue/enqueue-dev/blob/master/docs/index.md) +* [Questions](https://gitter.im/php-enqueue/Lobby) +* [Issue Tracker](https://github.com/php-enqueue/enqueue-dev/issues) + +## Developed by Forma-Pro + +Forma-Pro is a full stack development company which interests also spread to open source development. +Being a team of strong professionals we have an aim an ability to help community by developing cutting edge solutions in the areas of e-commerce, docker & microservice oriented architecture where we have accumulated a huge many-years experience. +Our main specialization is Symfony framework based solution, but we are always looking to the technologies that allow us to do our job the best way. We are committed to creating solutions that revolutionize the way how things are developed in aspects of architecture & scalability. + +If you have any questions and inquires about our open source development, this product particularly or any other matter feel free to contact at opensource@forma-pro.com + +## License + +It is released under the [MIT License](LICENSE). \ No newline at end of file From 3322ee19b6ae5c923cec161516079c32666a327e Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 7 Aug 2017 16:24:36 +0300 Subject: [PATCH 75/76] [amqp][delay] add docs --- docs/transport/amqp.md | 26 ++++++++++++++++++++++++++ docs/transport/amqp_bunny.md | 26 ++++++++++++++++++++++++++ docs/transport/amqp_lib.md | 26 ++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/docs/transport/amqp.md b/docs/transport/amqp.md index 97ea37fdf..8fd374521 100644 --- a/docs/transport/amqp.md +++ b/docs/transport/amqp.md @@ -12,6 +12,7 @@ Build on top of [php amqp extension](https://github.com/pdezwart/php-amqp). * [Send message to queue](#send-message-to-queue) * [Send priority message](#send-priority-message) * [Send expiration message](#send-expiration-message) +* [Send delayed message](#send-delayed-message) * [Consume message](#consume-message) * [Purge queue messages](#purge-queue-messages) @@ -163,6 +164,31 @@ $psrContext->createProducer() ; ``` +## Send delayed message + +AMQP specification says nothing about message delaying hence the producer throws `DeliveryDelayNotSupportedException`. +Though the producer (and the context) accepts a delivry delay strategy and if it is set it uses it to send delayed message. +The `enqueue/amqp-tools` package provides two RabbitMQ delay strategies, to use them you have to install that package + +```php +createMessage('Hello world!'); + +$psrContext->createProducer() + ->setDelayStrategy(new RabbitMqDlxDelayStrategy()) + ->setDeliveryDelay(5000) // 5 sec + + ->send($fooQueue, $message) +; +```` + ## Consume message: ```php diff --git a/docs/transport/amqp_bunny.md b/docs/transport/amqp_bunny.md index 69afaad76..28c78c8cc 100644 --- a/docs/transport/amqp_bunny.md +++ b/docs/transport/amqp_bunny.md @@ -12,6 +12,7 @@ Build on top of [bunny lib](https://github.com/jakubkulhan/bunny). * [Send message to queue](#send-message-to-queue) * [Send priority message](#send-priority-message) * [Send expiration message](#send-expiration-message) +* [Send delayed message](#send-delayed-message) * [Consume message](#consume-message) * [Purge queue messages](#purge-queue-messages) @@ -163,6 +164,31 @@ $psrContext->createProducer() ; ``` +## Send delayed message + +AMQP specification says nothing about message delaying hence the producer throws `DeliveryDelayNotSupportedException`. +Though the producer (and the context) accepts a delivry delay strategy and if it is set it uses it to send delayed message. +The `enqueue/amqp-tools` package provides two RabbitMQ delay strategies, to use them you have to install that package + +```php +createMessage('Hello world!'); + +$psrContext->createProducer() + ->setDelayStrategy(new RabbitMqDlxDelayStrategy()) + ->setDeliveryDelay(5000) // 5 sec + + ->send($fooQueue, $message) +; +```` + ## Consume message: ```php diff --git a/docs/transport/amqp_lib.md b/docs/transport/amqp_lib.md index b087c1b47..59061352d 100644 --- a/docs/transport/amqp_lib.md +++ b/docs/transport/amqp_lib.md @@ -12,6 +12,7 @@ Build on top of [php amqp lib](https://github.com/php-amqplib/php-amqplib). * [Send message to queue](#send-message-to-queue) * [Send priority message](#send-priority-message) * [Send expiration message](#send-expiration-message) +* [Send delayed message](#send-delayed-message) * [Consume message](#consume-message) * [Purge queue messages](#purge-queue-messages) @@ -163,6 +164,31 @@ $psrContext->createProducer() ; ``` +## Send delayed message + +AMQP specification says nothing about message delaying hence the producer throws `DeliveryDelayNotSupportedException`. +Though the producer (and the context) accepts a delivry delay strategy and if it is set it uses it to send delayed message. +The `enqueue/amqp-tools` package provides two RabbitMQ delay strategies, to use them you have to install that package + +```php +createMessage('Hello world!'); + +$psrContext->createProducer() + ->setDelayStrategy(new RabbitMqDlxDelayStrategy()) + ->setDeliveryDelay(5000) // 5 sec + + ->send($fooQueue, $message) +; +```` + ## Consume message: ```php From c12b4afbfca64fe04a57f45dc3143e4d312785d5 Mon Sep 17 00:00:00 2001 From: Maksim Kotlyar Date: Mon, 7 Aug 2017 16:24:54 +0300 Subject: [PATCH 76/76] [amqp][delay] delay strategy aware setter must return self. --- pkg/amqp-tools/DelayStrategyAware.php | 2 ++ pkg/amqp-tools/DelayStrategyAwareTrait.php | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/pkg/amqp-tools/DelayStrategyAware.php b/pkg/amqp-tools/DelayStrategyAware.php index cff5b5e4f..2aedc453d 100644 --- a/pkg/amqp-tools/DelayStrategyAware.php +++ b/pkg/amqp-tools/DelayStrategyAware.php @@ -6,6 +6,8 @@ interface DelayStrategyAware { /** * @param DelayStrategy $delayStrategy + * + * @return self */ public function setDelayStrategy(DelayStrategy $delayStrategy = null); } diff --git a/pkg/amqp-tools/DelayStrategyAwareTrait.php b/pkg/amqp-tools/DelayStrategyAwareTrait.php index 8313b4d49..fc9bd696f 100644 --- a/pkg/amqp-tools/DelayStrategyAwareTrait.php +++ b/pkg/amqp-tools/DelayStrategyAwareTrait.php @@ -11,9 +11,13 @@ trait DelayStrategyAwareTrait /** * @param DelayStrategy|null $delayStrategy + * + * @return self */ public function setDelayStrategy(DelayStrategy $delayStrategy = null) { $this->delayStrategy = $delayStrategy; + + return $this; } }