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.