Resolve cache images in background
By default, the LiipImagineBundle processes images on demand. When an image is requested that has not yet been cached with the requested filter set, the controller applies the filters and caches the result. Then it redirects the client to the generated image file.
This works without any further tooling. There are some important disadvantages however:
- Applying all the filters to an image can take a lot of time and memory;
- The images have to be processed by the web server answering web requests. This increases the load on the server and may affect performance;
- The resolve controller URL is different from the cached image URL. When the image needs to be generated, the cached HTML page contains the URL to the controller. If you are caching the HTML, all clients using the cache are sent to the controller and need to go through the redirect even though it would be unnecessary.
To prepare the cached images in advance, the LiipImagineBundle allows you to use a message queue to run a worker that warms up the cache asynchronously. Your application has to send messages about the images as it becomes aware of them (file upload, import processes, ...) and you need to run workers for the message queue.
Symfony Messenger
This bundle provides an integration with Symfony Messenger. When enabled, it provides a message handler to consume warmup messages.
Step 1: Install
First, install symfony/messenger with composer:
1
composer require symfony/messenger
1 2 3 4 5 6 7 8 9 10 11 12
# config/packages/messenger.yaml
framework:
messenger:
transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
liip_imagine: '%env(MESSENGER_TRANSPORT_DSN)%'
sync: 'sync://'
routing:
# Route your messages to the transports
'Liip\ImagineBundle\Message\WarmupCache': liip_imagine
Step 2: Configure LiipImagineBundle
We need to instruct LiipImagineBundle to load the message handler that consumes the warmup messages and prepares the cached images in a separate process not tied to web requests.
1 2 3 4
# config/packages/liip_imagine.yaml
liip_imagine:
messenger: true
Step 3: Run consumers
We need to run at least one consumer for the messages:
1
php bin/console messenger:consume liip_imagine --time-limit=3600 --memory-limit=256M
You can run the consumers on a separate machine, as long as it shares the same storage for the cached images. In a cloud system, you could even scale consumers based on the queue size to get fast processing without tying up resources that would do nothing most of the time.
Step 4: Send WarmupCache message
The last step is to let the message consumer know about images that it needs to cache. When we reference the image in a Twig template, it is too late to use the message system.
Dispatch a message with the original image path (as you would use it in Twig). You may specify which filter sets to warm up, or leave that out to have the message consumer warm up all available filter sets.
Existing cached images are by default not replaced. You can force cache recreation. If force
is
set, cached images are recreated. Force is useful if you replace images with new versions that have
the same file name as before.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
<?php
use Liip\ImagineBundle\Message\WarmupCache;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Messenger\MessageBusInterface;
class DefaultController extends AbstractController
{
public function index(MessageBusInterface $messageBus)
{
// warmup all caches
$messageBus->dispatch(new WarmupCache('the/path/img.png'));
// warmup specific cache
$messageBus->dispatch(new WarmupCache('the/path/img.png', ['fooFilter']));
// force warmup (removes the cache if exists)
$messageBus->dispatch(new WarmupCache('the/path/img.png', null, true));
}
}
Enqueue (deprecated)
The enqueue library integration is deprecated in favor of the Symfony Messenger integration.
Enqueue integration will be removed in the next major version.
Step 1: Install EnqueueBundle
First, we have to install EnqueueBundle. You have to basically use composer to install the bundle, register it to AppKernel and adjust settings. Here's the smallest configuration without any extra dependencies. It is based on filesystem transport.
1 2 3 4 5 6
# app/config/config.yml
enqueue:
default:
transport: 'file://%kernel.root_dir%/../var/queues'
client: ~
Step 2: Configure LiipImagineBundle
At this step we instruct LiipImagineBundle to load some extra stuff required to process images in background.
1 2 3 4
# app/config/config.yml
liip_imagine:
enqueue: true
Step 3: Run consumers
Before we can start using it we need a pool of consumers (at least one) to be working in background. Here's how you can run it:
1
./bin/console enqueue:consume --setup-broker -vvv
Step 4: Send resolve cache message
You have to send a message in order to process images in background. The message must contain the original image path (in terms of LiipImagineBundle). If you do not define filters, the background process will resolve cache for all available filters. If the cache already exists, the background process does not recreate it by default. You can force cache to be recreated and in this case the cached image is removed and a new one replaces it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
<?php
use Enqueue\Client\ProducerInterface;
use Liip\ImagineBundle\Async\Commands;
use Liip\ImagineBundle\Async\ResolveCache;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* @var ContainerInterface $container
* @var ProducerInterface $producer
*/
$producer = $container->get(ProducerInterface::class);
// resolve all caches
$producer->sendCommand(Commands::RESOLVE_CACHE, new ResolveCache('the/path/img.png'));
// resolve specific cache
$producer->sendCommand(Commands::RESOLVE_CACHE, new ResolveCache('the/path/img.png', array('fooFilter')));
// force resolve (removes the cache if exists)
$producer->sendCommand(Commands::RESOLVE_CACHE, new ResolveCache('the/path/img.png', null, true));
// send command and wait for reply
$reply = $producer->sendCommand(Commands::RESOLVE_CACHE, new ResolveCache('the/path/img.png', null, true), true);
$replyMessage = $reply->receive(20000); // wait for 20 sec