Skip to content

Commit

Permalink
Merge pull request #6 from Neverdane/feature/sqs-bulk-messages
Browse files Browse the repository at this point in the history
Feature/sqs bulk messages
  • Loading branch information
tejerka committed Jan 27, 2016
2 parents d052491 + a9914db commit f35e8e1
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 21 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Queue Client Changelog

## v1.0.1

- Send SQS messages in batch

## v1.0.0

- Initial commit
38 changes: 38 additions & 0 deletions src/Adapter/AbstractAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace ReputationVIP\QueueClient\Adapter;

use ReputationVIP\QueueClient\QueueClientInterface;

class AbstractAdapter
{

/**
* @param string $queueName
* @param array $messages
* @param string $priority
*
* @return QueueClientInterface
*/
public function addMessages($queueName, $messages, $priority = null)
{
foreach ($messages as $message) {
$this->addMessage($queueName, $message, $priority);
}

return $this;
}

/**
* @param string $queueName
* @param mixed $message
* @param string $priority
*
* @return AdapterInterface
*/
public function addMessage($queueName, $message, $priority = null)
{
return $this;
}

}
2 changes: 1 addition & 1 deletion src/Adapter/FileAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;

class FileAdapter implements AdapterInterface
class FileAdapter extends AbstractAdapter implements AdapterInterface
{
const QUEUE_FILE_EXTENSION = 'queue';
const MAX_NB_MESSAGES = 10;
Expand Down
2 changes: 1 addition & 1 deletion src/Adapter/MemoryAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use ReputationVIP\QueueClient\PriorityHandler\StandardPriorityHandler;
use SplQueue;

class MemoryAdapter implements AdapterInterface
class MemoryAdapter extends AbstractAdapter implements AdapterInterface
{
const MAX_TIME_IN_FLIGHT = 30;

Expand Down
10 changes: 1 addition & 9 deletions src/Adapter/NullAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use ReputationVIP\QueueClient\PriorityHandler\PriorityHandlerInterface;
use ReputationVIP\QueueClient\PriorityHandler\StandardPriorityHandler;

class NullAdapter implements AdapterInterface
class NullAdapter extends AbstractAdapter implements AdapterInterface
{

/** @var PriorityHandlerInterface $priorityHandler */
Expand All @@ -23,14 +23,6 @@ public function __construct(PriorityHandlerInterface $priorityHandler = null)
$this->priorityHandler = $priorityHandler;
}

/**
* @inheritdoc
*/
public function addMessage($queueName, $message, $priority = null)
{
return $this;
}

/**
* @inheritdoc
*/
Expand Down
48 changes: 47 additions & 1 deletion src/Adapter/SQSAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use ReputationVIP\QueueClient\PriorityHandler\PriorityHandlerInterface;
use ReputationVIP\QueueClient\PriorityHandler\StandardPriorityHandler;

class SQSAdapter implements AdapterInterface
class SQSAdapter extends AbstractAdapter implements AdapterInterface
{
/**
* @var SqsClient
Expand All @@ -19,6 +19,7 @@ class SQSAdapter implements AdapterInterface
private $priorityHandler;

const MAX_NB_MESSAGES = 10;
const SENT_MESSAGES_BATCH_SIZE = 10;
const PRIORITY_SEPARATOR = '-';

/**
Expand Down Expand Up @@ -51,6 +52,51 @@ public function __construct(SqsClient $sqsClient, PriorityHandlerInterface $prio
return $this;
}

/**
* @inheritdoc
*/
public function addMessages($queueName, $messages, $priority = null)
{
if (null === $priority) {
$priority = $this->priorityHandler->getDefault();
}

if (empty($queueName)) {
throw new InvalidArgumentException('Parameter queueName empty or not defined.');
}

$batchMessages = [];
$batchesCount = 0;
$blockCounter = 0;

foreach ($messages as $index => $message) {
if (empty($message)) {
throw new InvalidArgumentException('Parameter message empty or not defined.');
}
$messageData = [
'Id' => (string) $index,
'MessageBody' => serialize($message)
];
if ($blockCounter >= self::SENT_MESSAGES_BATCH_SIZE) {
$blockCounter = 0;
$batchesCount++;
} else {
$blockCounter++;
}
$batchMessages[$batchesCount][] = $messageData;
}

foreach ($batchMessages as $messages) {
$queueUrl = $this->sqsClient->getQueueUrl(['QueueName' => $this->getQueueNameWithPrioritySuffix($queueName, $priority)])->get('QueueUrl');
$this->sqsClient->sendMessageBatch([
'QueueUrl' => $queueUrl,
'Entries' => $messages,
]);
}

return $this;
}

/**
* @inheritdoc
*
Expand Down
17 changes: 8 additions & 9 deletions src/QueueClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,10 @@ public function __construct(AdapterInterface $adapter = null)
*/
public function addMessage($queueName, $message, $priority = null)
{
$queues = $this->resolveAliasQueueName($queueName);
if (is_array($queues)) {
foreach ($queues as $queue) {
$this->adapter->addMessage($queue, $message, $priority);
}
} else {
$this->adapter->addMessage($queues, $message, $priority);
$queues = (array) $this->resolveAliasQueueName($queueName);

foreach ($queues as $queue) {
$this->adapter->addMessage($queue, $message, $priority);
}

return $this;
Expand All @@ -70,8 +67,10 @@ public function addMessage($queueName, $message, $priority = null)
*/
public function addMessages($queueName, $messages, $priority = null)
{
foreach ($messages as $message) {
$this->addMessage($queueName, $message, $priority);
$queues = (array) $this->resolveAliasQueueName($queueName);

foreach ($queues as $queue) {
$this->adapter->addMessages($queue, $messages, $priority);
}

return $this;
Expand Down
6 changes: 6 additions & 0 deletions tests/units/Adapter/NullAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ public function testNullAdapterAddMessage()
$this->given($NullAdapter)->class($NullAdapter->addMessage('testQueue', 'test Message one'))->hasInterface('\ReputationVIP\QueueClient\Adapter\AdapterInterface');
}

public function testNullAdapterAddMessages()
{
$NullAdapter = new \ReputationVIP\QueueClient\Adapter\NullAdapter();
$this->given($NullAdapter)->class($NullAdapter->addMessages('testQueue', ['test Message one']))->hasInterface('\ReputationVIP\QueueClient\Adapter\AdapterInterface');
}

public function testNullAdapterGetMessages()
{
$NullAdapter = new \ReputationVIP\QueueClient\Adapter\NullAdapter();
Expand Down
41 changes: 41 additions & 0 deletions tests/units/Adapter/SQSAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,47 @@ public function testSQSAdapterAddMessage()
->class($SQSAdapter->addMessage('testQueue', 'test message'))->hasInterface('\ReputationVIP\QueueClient\Adapter\AdapterInterface');
}

public function testSQSAdapterAddMessages()
{
$this->mockGenerator->orphanize('__construct');
$this->mockGenerator->shuntParentClassCalls();
$mockSqsClient = new \mock\Aws\Sqs\SqsClient;
$mockQueueUrlModel = new \mock\Guzzle\Service\Resource\Model;
$SQSAdapter = new \ReputationVIP\QueueClient\Adapter\SQSAdapter($mockSqsClient);

$mockSqsClient->getMockController()->getQueueUrl = function () use($mockQueueUrlModel) {
return $mockQueueUrlModel;
};
$mockSqsClient->getMockController()->sendMessageBatch = function () {
};
$this->given($SQSAdapter)
->class($SQSAdapter->addMessages('testQueue', array_fill(0, 11, 'test message')))->hasInterface('\ReputationVIP\QueueClient\Adapter\AdapterInterface');
}

public function testSQSAdapterAddMessagesWithEmptyMessage()
{
$this->mockGenerator->orphanize('__construct');
$this->mockGenerator->shuntParentClassCalls();
$mockSqsClient = new \mock\Aws\Sqs\SqsClient;
$SQSAdapter = new \ReputationVIP\QueueClient\Adapter\SQSAdapter($mockSqsClient);

$this->exception(function() use($SQSAdapter) {
$SQSAdapter->addMessages('testQueue', ['test message', '']);
});
}

public function testSQSAdapterAddMessagesWithEmptyQueueName()
{
$this->mockGenerator->orphanize('__construct');
$this->mockGenerator->shuntParentClassCalls();
$mockSqsClient = new \mock\Aws\Sqs\SqsClient;
$SQSAdapter = new \ReputationVIP\QueueClient\Adapter\SQSAdapter($mockSqsClient);

$this->exception(function() use($SQSAdapter) {
$SQSAdapter->addMessages('', ['']);
});
}

public function testSQSAdapterGetMessagesWithEmptyQueueName()
{
$this->mockGenerator->orphanize('__construct');
Expand Down

0 comments on commit f35e8e1

Please sign in to comment.