Symfony Messenger bileşeni, uygulamalara veya uygulamalardan mesaj gönderip almamıza yardımcı olur. Bu, işleri RabbitMQ gibi mesaj sıralarına koymayı da içerir. Bu örnekte, resim boyutlarını değiştirme işlerini RabbitMQ kuyruğuna koyacağız ve bunları daha sonra tüketeceğiz.


RabbitMQ server


Aşağıdaki docker-compose.yml dosyası ile bir tane RabbitMQ docker container yaratacağız.


version: '3'

services:

rabbitmq:
image: rabbitmq:3.7.5-management
hostname: rabbitmq
user: rabbitmq
ports:
- 5672:5672
- 15672:15672
volumes:
- ./data/rabbitmq:/var/lib/rabbitmq/mnesia/rabbit@app-rabbitmq:cached
environment:
RABBITMQ_ERLANG_COOKIE: 6085e2412b6fa88647466c6a81c0cea0
RABBITMQ_DEFAULT_USER: rabbitmq
RABBITMQ_DEFAULT_PASS: rabbitmq
RABBITMQ_DEFAULT_VHOST: /

Container'ı yaratmak için $ docker-compose up -d komutunu kullanıyoruz.


$ docker-compose ps
Name Command State Ports
---------------------------------------------------------------------------------------------------------------------------------------------------------
rabbitmq_rabbitmq_1 docker-entrypoint.sh rabbi ... Up 15671/tcp, 0.0.0.0:15672->15672/tcp, 25672/tcp, 4369/tcp, 5671/tcp, 0.0.0.0:5672->5672/tcp

Bu container'ın çalıştığı makinenin IP adresi 192.168.99.30 olup, Symfony uygulamamız ve bir internet tarayıcıdan erişmek için kullanacağız. GUI için http://192.168.99.30:15672 adresine gidip rabbitmq:rabbitmq ile login olabilirsiniz. Symfony uygulamamızda işleri sıraya koymak için 5672 portunu kullanacağız.


Symfony uygulaması


Hazırlık


İşleri sıraya koyabilmek için AMQP broker kurulumunu yapalım.


$ sudo apt-get -y install gcc make autoconf libc-dev pkg-config
$ sudo apt-get update
$ sudo apt-get -y install libssl-dev
$ sudo apt-get -y install librabbitmq-dev
$ sudo pecl install amqp # Hit enter if a question is asked
$ sudo apt-get -y install php7.2-amqp

extension=amqp.so eklentisini /etc/php/7.2/fpm/php.ini dosyasına ekleyin ve sudo service php7.2-fpm restart komutu ile php-fpm'i yeniden başlatın. Daha sonra amqp uzantısını kontrol edin.


$ php -i | grep -i amqp
/etc/php/7.2/cli/conf.d/20-amqp.ini,
amqp
AMQP protocol version => 0-9-1
amqp.auto_ack => 0 => 0
amqp.cacert => no value => no value
amqp.cert => no value => no value
amqp.channel_max => 256 => 256
amqp.connect_timeout => 0 => 0
amqp.frame_max => 131072 => 131072
amqp.heartbeat => 0 => 0
amqp.host => localhost => localhost
amqp.key => no value => no value
amqp.login => guest => guest
amqp.password => guest => guest
amqp.port => 5672 => 5672
amqp.prefetch_count => 3 => 3
amqp.read_timeout => 0 => 0
amqp.sasl_method => 0 => 0
amqp.timeout => no value => no value
amqp.verify => 1 => 1
amqp.vhost => / => /
amqp.write_timeout => 0 => 0

Messenger bileşeni


Kurulum için composer require symfony/messenger komutunu kullanın. Mevcut olan AMQP transport bileşenini kullanabilmek için, Symfony Serializer bileşenini composer require symfony/serializer-pack komutu ile kurmanız gerekecek. Ama bu işlemi yapmadan önce uygulamanızı test edin çünkü, gerekli olan serializer ve normalizer daha önceden kurulmuş olabilirler.


Konfigürasyon


# .env

MESSENGER_TRANSPORT_DSN=amqp://rabbitmq:rabbitmq@192.168.99.30:5672/%2f

Classlar


Bu işleri sıraya koyduğumuz yerdir - buna "message producer" diyebiliriz.


# Controller/ImageController.php

declare(strict_types=1);

namespace App\Controller;

use App\MessageBus\Message\Image\Resize;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Annotation\Route;

/**
* @Route("/images")
*/
class ImageController
{
private $messageBus;

public function __construct(MessageBusInterface $messageBus)
{
$this->messageBus = $messageBus;
}

/**
* @Route("", methods={"GET"})
*/
public function getAll(): Response
{
$message = new Resize('ball.png');

$this->messageBus->dispatch($message);

return new Response('Good Job!');
}
}

Bu asıl işin içeriğidir - json format olarak.


# MessageBus/Message/Image/Resize.php

declare(strict_types=1);

namespace App\MessageBus\Message\Image;

class Resize
{
private $path;

public function __construct(string $path)
{
$this->path = $path;
}

public function getPath(): string
{
return $this->path;
}
}

Bu sıradaki işleri tek tek işlediğimiz yerdir - buna "message consumer" diyebilirsiniz.


# MessageBus/Handler/Image/ResizeHandler.php

declare(strict_types=1);

namespace App\MessageBus\Handler\Image;

use App\MessageBus\Message\Image\Resize;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;

class ResizeHandler implements MessageHandlerInterface
{
public function __invoke(Resize $message)
{
echo sprintf('The image "%s" is being resized...'.PHP_EOL, $message->getPath());
sleep(2); // Assume than message resizing takes 2 seconds
echo 'The image has been resized!'.PHP_EOL;
echo 'Moving on to next message in the queue.'.PHP_EOL.PHP_EOL;
}
}

Bu da son olarak yapılacak olan konfigürasyondur.


# config/packages/messenger.yaml

# Version 1
framework:
messenger:
transports:
amqp_image_resize: '%env(MESSENGER_TRANSPORT_DSN)%/image_resize'

routing:
'App\MessageBus\Message\Image\Resize': amqp_image_resize

# Version 2
framework:
messenger:
transports:
amqp_image_resize:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
exchange:
name: image_resize_ex
type: fanout
queue:
name: image_resize_qu

routing:
'App\MessageBus\Message\Image\Resize': amqp_image_resize

Yukarıdaki konfigürasyonların her ikiside aynı işi yapıyor ama biz birincisini kullanacağız. Bunun yaptığı şey App\MessageBus\Message\Image\Resize işlerini image_resize exchange/queue'ye yönlendirmektir.


Test


İşleri sıraya koymak


İlk kez GET /images adresini çağırdığımızda, Symfony aşağıdaki işlemi yapar.



İşleri işlemek


$ bin/console messenger:consume-messages amqp_image_resize
The image "ball.png" is being resized...
The image has been resized!
Moving on to next message in the queue.

The image "ball.png" is being resized...
The image has been resized!
Moving on to next message in the queue.

The image "ball.png" is being resized...
The image has been resized!
Moving on to next message in the queue.