19/01/2019 - RABBITMQ, SYMFONY
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.
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.
İş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
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.
# .env
MESSENGER_TRANSPORT_DSN=amqp://rabbitmq:rabbitmq@192.168.99.30:5672/%2f
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.
İlk kez GET /images adresini çağırdığımızda, Symfony aşağıdaki işlemi yapar.
image_resize isminde ve durable modunda fanout exchange yaratır.image_resize isminde ve durable modunda queue yaratır.{"path":"ball.png"} olacaktır ki bu da Resize mesaj classıdır.$ 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.