Привет, Хабр!
Итак, решили внедрить асинхронные процессы в своё Symfony-приложение? Отличный выбор! А выбор RabbitMQ для этой задачи — вообще идеален: надёжный, быстрый и отлично работающий в связке с Symfony. Наша цель — научиться отправлять сообщения (скажем, сообщения о новых котиках) в очередь и плавно обрабатывать их.
Запуск RabbitMQ
Для начала понадобится сам RabbitMQ. Можно установить его напрямую или, как в большинстве проектов, с помощью Docker.
Добавляем в docker-compose.yml
сервис для RabbitMQ:
version: '3.8' services: rabbitmq: image: rabbitmq:3-management ports: - "5672:5672" # для общения с приложением - "15672:15672" # для панели управления environment: RABBITMQ_DEFAULT_USER: guest RABBITMQ_DEFAULT_PASS: guest
Теперь запускаем:
docker-compose up -d
Проверяем: панель управления RabbitMQ доступна по адресу http://localhost:15672
(логин и пароль — guest). Здесь можно управлять очередями, обменниками и проверять, как сообщения путешествуют по RabbitMQ.
Настройка Symfony Messenger
Теперь — к нашей основной задаче. Symfony Messenger — это мощный компонент, который облегчает отправку и получение сообщений. В нашем случае, это — сообщения о котиках. С помощью Messenger будем слать котиков в очередь и обрабатывать их с другой стороны.
Чтобы начать, нужно установить пару зависимостей:
composer require symfony/messenger symfony/amqp-messenger
В файле config/packages/messenger.yaml
добавляем транспорт для RabbitMQ. Это будет «транспорт асинхронных сообщений»:
framework: messenger: transports: async: '%env(MESSENGER_TRANSPORT_DSN)%' # Основной транспорт routing: 'App\Message\CatMessage': async # Назначаем маршрут для наших сообщений
Здесь мы указали, что все сообщения типа CatMessage
будут отправляться в очередь «async».
Подключение к RabbitMQ
Добавляем следующую строку в файл .env
:
MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f
Тут мы указываем параметры подключения к RabbitMQ — дефолтные логин и пароль, адрес хоста и название виртуального хоста (%2f
— это код символа /
, он обозначает корневой виртуальный хост).
Создание сообщения CatMessage
Теперь создадим сообщение. В Symfony это — объект, который будет содержать данные о котике. Начнем с простого примера:
// src/Message/CatMessage.php namespace App\Message; class CatMessage { private string $name; private int $age; public function __construct(string $name, int $age) { $this->name = $name; $this->age = $age; } public function getName(): string { return $this->name; } public function getAge(): int { return $this->age; } }
Теперь есть простой объект сообщения с именем и возрастом котика. Это то, что мы будем отправлять в RabbitMQ.
Обработчик сообщения
Сообщения у нас есть, но их нужно кому-то обрабатывать. Создадим обработчик, который будет получать сообщения из очереди и обрабатывать их.
// src/MessageHandler/CatMessageHandler.php namespace App\MessageHandler; use App\Message\CatMessage; use Symfony\Component\Messenger\Handler\MessageHandlerInterface; class CatMessageHandler implements MessageHandlerInterface { public function __invoke(CatMessage $message) { // Представим, что обработчик добавляет котика в базу данных echo sprintf("Котик %s, возраст %d лет, успешно обработан!\n", $message->getName(), $message->getAge()); } }
Наш обработчик будет просто выводить информацию о котике, но в продакшене можно здесь сделать что-то полезное, например, добавить котика в базу данных.
Отправка сообщений
Пора отправить первого котика в очередь! Для создадим контроллер, который будет принимать запрос и отправлять CatMessage
через Symfony Messenger.
// src/Controller/CatController.php namespace App\Controller; use App\Message\CatMessage; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Messenger\MessageBusInterface; use Symfony\Component\Routing\Annotation\Route; class CatController { private MessageBusInterface $bus; public function __construct(MessageBusInterface $bus) { $this->bus = $bus; } #[Route('/send-cat', name: 'send_cat')] public function sendCat(): Response { $catMessage = new CatMessage('Барсик', 3); $this->bus->dispatch($catMessage); return new Response('Сообщение о котике отправлено!'); } }
Теперь можно перейти по адресу /send-cat
, и сообщение отправится в очередь RabbitMQ. Каждый раз, когда этот маршрут вызывается, новый котик добавляется в очередь.
Запуск консумера (обработчика)
Чтобы Symfony мог начать забирать сообщения из RabbitMQ и передавать их в обработчик, нужно запустить консумер:
php bin/console messenger:consume async
Теперь при каждом новом сообщении обработчик будет выводить информацию о котике.
Обработка ошибок и ретраи
Жизнь сурова: иногда обработка сообщений может завершиться с ошибкой. Symfony Messenger позволяет настраивать ретраи и логировать ошибки.
Для этого в messenger.yaml
добавим параметры:
framework: messenger: failure_transport: failed transports: async: '%env(MESSENGER_TRANSPORT_DSN)%' failed: 'doctrine://default?queue_name=failed' retry_strategy: async: max_retries: 3 delay: 1000 # Задержка между ретраями multiplier: 2 # Увеличиваем задержку на 2 раза max_delay: 30000 # Максимальная задержка между ретраями
Здесь настроили стратегию ретраев, которая повторит отправку сообщения до трех раз с увеличением задержки. Если сообщение так и не будет обработано, оно переместится в failed
-транспорт, где мы сможем его повторно отправить позже.
Инлайн-классы
Если хочется экспериментировать с инлайн-классами (например, в тестовых сценариях), вы можно создать обработчик с помощью анонимных классов:
$handler = new class implements MessageHandlerInterface { public function __invoke(CatMessage $message) { echo sprintf("Инлайн-обработчик: Котик %s, возраст %d лет, был обработан.\n", $message->getName(), $message->getAge()); } };
Инлайн-классы полезны для быстрого прототипирования, но не стоит злоупотреблять!
Если у вас есть чем дополнить или поделиться своим опытом работы с RabbitMQ в Symfony — пишите в комментариях! Всегда интересно узнать.
Также спешу напомнить, что сегодня, 12 ноября, в 20:00 пройдет открытый урок на тему «Надёжная отправка и получение сообщений через RabbitMQ в Symfony». Если интересно, узнать подробности и записаться можно на странице курса «Symfony Framework».
ссылка на оригинал статьи https://habr.com/ru/articles/856238/
Добавить комментарий