Skip to content

Commit

Permalink
Resolve image caches in background. Using message queue.
Browse files Browse the repository at this point in the history
  • Loading branch information
makasim committed May 4, 2017
1 parent 09dc0e1 commit cf0cdbf
Show file tree
Hide file tree
Showing 13 changed files with 869 additions and 2 deletions.
5 changes: 4 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ matrix:
env: SYMFONY_VERSION=2.3.x-dev
- php: 5.6
env: SYMFONY_VERSION=2.7.x-dev
- php: 5.6
env: SYMFONY_VERSION=2.8.x-dev WITH_ENQUEUE=true
- php: 7.1
env: SYMFONY_VERSION=3.0.x-dev
- php: 7.1
env: SYMFONY_VERSION=3.1.x-dev
- php: 7.1
env: SYMFONY_VERSION=3.2.x-dev
- php: 7.1
env: SYMFONY_VERSION=3.3.x-dev
env: SYMFONY_VERSION=3.3.x-dev WITH_ENQUEUE=true
- php: 7.1
env: SYMFONY_VERSION=dev-master
allow_failures:
Expand All @@ -55,6 +57,7 @@ before_install:
- if [ "${TRAVIS_PHP_VERSION}" != "hhvm" ] && [ "${TRAVIS_PHP_VERSION:0:3}" != "5.3" ]; then composer require --no-update --dev league/flysystem:~1.0; fi;
- if [ "${TRAVIS_PHP_VERSION}" != "hhvm" ] && [ "${TRAVIS_PHP_VERSION:0:1}" != "7" ]; then yes "" | pecl -q install -f mongo; composer require --no-update --dev doctrine/mongodb-odm:~1.0; fi;
- if [ "${TRAVIS_PHP_VERSION}" != "hhvm" ] && [ "${TRAVIS_PHP_VERSION:0:1}" == "7" ]; then yes "" | pecl -q install -f mongodb; travis_retry composer require --dev alcaeus/mongo-php-adapter:~1.0; composer require --no-update --dev doctrine/mongodb-odm:~1.0; fi
- if [ "$WITH_ENQUEUE" = true ] ; then composer require --no-update --dev enqueue/enqueue-bundle:^0.3.6; fi;

install:
- travis_retry composer update $COMPOSER_FLAGS
Expand Down
71 changes: 71 additions & 0 deletions Async/CacheResolved.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php
namespace Liip\ImagineBundle\Async;

use Enqueue\Util\JSON;

class CacheResolved implements \JsonSerializable
{
/**
* @var string
*/
private $path;

/**
* @var \string[]
*/
private $uris;

/**
* @param string $path
* @param string[]|null $uris
*/
public function __construct($path, array $uris)
{
$this->path = $path;
$this->uris = $uris;
}

/**
* @return string
*/
public function getPath()
{
return $this->path;
}

/**
* @return \string[]
*/
public function getUris()
{
return $this->uris;
}

/**
* {@inheritdoc}
*/
public function jsonSerialize()
{
return array('path' => $this->path, 'uris' => $this->uris);
}

/**
* @param string $json
*
* @return static
*/
public static function jsonDeserialize($json)
{
$data = JSON::decode($json);

if (empty($data['path'])) {
throw new \LogicException('The message does not contain "path" but it is required.');
}

if (empty($data['uris'])) {
throw new \LogicException('The message uris must not be empty array.');
}

return new static($data['path'], $data['uris']);
}
}
86 changes: 86 additions & 0 deletions Async/ResolveCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php
namespace Liip\ImagineBundle\Async;

use Enqueue\Util\JSON;

class ResolveCache implements \JsonSerializable
{
/**
* @var string
*/
private $path;

/**
* @var array|null|\string[]
*/
private $filters;

/**
* @var bool
*/
private $force;

/**
* @param string $path
* @param string[]|null $filters
* @param bool $force
*/
public function __construct($path, array $filters = null, $force = false)
{
$this->path = $path;
$this->filters = $filters;
$this->force = $force;
}

/**
* @return string
*/
public function getPath()
{
return $this->path;
}

/**
* @return null|\string[]
*/
public function getFilters()
{
return $this->filters;
}

/**
* @return bool
*/
public function isForce()
{
return $this->force;
}

/**
* {@inheritdoc}
*/
public function jsonSerialize()
{
return array('path' => $this->path, 'filters' => $this->filters, 'force' => $this->force);
}

/**
* @param string $json
*
* @return static
*/
public static function jsonDeserialize($json)
{
$data = array_replace(array('path' => null, 'filters' => null, 'force' => false), JSON::decode($json));

if (false == $data['path']) {
throw new \LogicException('The message does not contain "path" but it is required.');
}

if (false == (is_null($data['filters']) || is_array($data['filters']))) {
throw new \LogicException('The message filters could be either null or array.');
}

return new static($data['path'], $data['filters'], $data['force']);
}
}
108 changes: 108 additions & 0 deletions Async/ResolveCacheProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php
namespace Liip\ImagineBundle\Async;

use Enqueue\Client\ProducerInterface;
use Enqueue\Client\TopicSubscriberInterface;
use Enqueue\Consumption\QueueSubscriberInterface;
use Enqueue\Consumption\Result;
use Enqueue\Psr\PsrContext;
use Enqueue\Psr\PsrMessage;
use Enqueue\Psr\PsrProcessor;
use Liip\ImagineBundle\Imagine\Cache\CacheManager;
use Liip\ImagineBundle\Imagine\Data\DataManager;
use Liip\ImagineBundle\Imagine\Filter\FilterManager;

class ResolveCacheProcessor implements PsrProcessor, TopicSubscriberInterface, QueueSubscriberInterface
{
/**
* @var CacheManager
*/
private $cacheManager;

/**
* @var FilterManager
*/
private $filterManager;

/**
* @var DataManager
*/
private $dataManager;

/**
* @var ProducerInterface
*/
private $producer;

/**
* @param CacheManager $cacheManager
* @param FilterManager $filterManager
* @param DataManager $dataManager
* @param ProducerInterface $producer
*/
public function __construct(
CacheManager $cacheManager,
FilterManager $filterManager,
DataManager $dataManager,
ProducerInterface $producer
) {
$this->cacheManager = $cacheManager;
$this->filterManager = $filterManager;
$this->dataManager = $dataManager;
$this->producer = $producer;
}

/**
* {@inheritdoc}
*/
public function process(PsrMessage $psrMessage, PsrContext $psrContext)
{
try {
$message = ResolveCache::jsonDeserialize($psrMessage->getBody());
} catch (\Exception $e) {
return Result::reject($e->getMessage());
}

$filters = $message->getFilters() ?: $this->filterManager->getFilterConfiguration()->all();
$path = $message->getPath();
$results = array();
foreach ($filters as $filter => $config) {
if ($this->cacheManager->isStored($path, $filter) && $message->isForce()) {
$this->cacheManager->remove($path, $filter);
}

if (false == $this->cacheManager->isStored($path, $filter)) {
$binary = $this->dataManager->find($filter, $path);
$this->cacheManager->store(
$this->filterManager->applyFilter($binary, $filter),
$path,
$filter
);
}

$results[$filter] = $this->cacheManager->resolve($path, $filter);
}

$this->producer->send(Topics::CACHE_RESOLVED, new CacheResolved($path, $results));

return self::ACK;
}

/**
* {@inheritdoc}
*/
public static function getSubscribedTopics()
{
return array(
Topics::RESOLVE_CACHE => array('queueName' => Topics::RESOLVE_CACHE, 'queueNameHardcoded' => true),
);
}

/**
* {@inheritdoc}
*/
public static function getSubscribedQueues()
{
return array(Topics::RESOLVE_CACHE);
}
}
9 changes: 9 additions & 0 deletions Async/Topics.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
namespace Liip\ImagineBundle\Async;

class Topics
{
const RESOLVE_CACHE = 'liip_imagine_resolve_cache';

const CACHE_RESOLVED = 'liip_imagine_cache_resolved';
}
1 change: 1 addition & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ public function getConfigTreeBuilder()
->end()
->end()
->end()
->booleanNode('enqueue')->defaultFalse()->info('Enables integration with enqueue if set true. Allows resolve image caches in background by sending messages to MQ.')->end()
->end();

return $treeBuilder;
Expand Down
4 changes: 4 additions & 0 deletions DependencyInjection/LiipImagineExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ public function load(array $configs, ContainerBuilder $container)
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('imagine.xml');

if ($config['enqueue']) {
$loader->load('enqueue.xml');
}

$this->setFactories($container);

if (interface_exists('Imagine\Image\Metadata\MetadataReaderInterface')) {
Expand Down
16 changes: 16 additions & 0 deletions Resources/config/enqueue.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<service id="liip_imagine.async.resolve_cache_processor" class="Liip\ImagineBundle\Async\ResolveCacheProcessor">
<argument type="service" id="liip_imagine.cache.manager" />
<argument type="service" id="liip_imagine.filter.manager" />
<argument type="service" id="liip_imagine.data.manager" />
<argument type="service" id="enqueue.producer" />

<tag name="enqueue.client.processor" />
</service>
</services>
</container>
Loading

0 comments on commit cf0cdbf

Please sign in to comment.