Разворачиваем RabbitMQ в Docker контейнере
Начнем с установки RabbitMQ, развернем его в отдельном Docker контейнере. Для этого добавим в ваш docker-compose.yaml строчки:
rabbitmq:
image: rabbitmq:4.3.2-management-alpine
env_file:
- app/.env.local
ports:
- "8083:15672"
volumes:
- rabbitmq_data:/var/lib/rabbitmq
restart: always
в моем случае, пользователь RABBITMQ_DEFAULT_USER и пароль RABBITMQ_DEFAULT_PASS указаны в локальном файле .env.local поэтому они автоматически подтянутся оттуда.
- "8083:15672" Пробрасываем только порт для вебморды самого RabbitMQ
Также указал виртуальный хост в файле env.local - RABBITMQ_DEFAULT_VHOST
Устанавливаем нужные пакеты в Symfony для работы с брокером
Для работы нам потребуется установить два пакета:
composer require symfony/messenger symfony/amqp-messenger
При установке может возникнуть ошибка, потому что на php не установлено расширение для работы с протоколом AMQP
После установки пакетов приписываем DSN для подключения к RabbitMQ в моем случае это:
MESSENGER_TRANSPORT_DSN=amqp://guest:guest@rabbitmq:5672/myblog
Настраиваем первый обмен с очередью
Для примера я сделаю событие на авторизацию пользователя на сайте, а внутри обработчика буду просто записывать в лог сообщение, что событие прочитано.
И так для начала сконфигурируем messenger.yaml:
framework:
messenger:
# Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
# failure_transport: failed
transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
# async: '%env(MESSENGER_TRANSPORT_DSN)%'
# failed: 'doctrine://default?queue_name=failed'
sync: 'sync://'
external_events:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
auto_setup: true
exchange:
name: user_events_exchange
type: direct
default_publish_routing_key: user_logged_in
queues:
user_login_queue:
binding_keys: [ user_logged_in ]
routing:
# Route your messages to the transports
# 'App\Message\YourMessage': async
'App\Message\UserLoggedInEvent': external_events
- Первым делом мы создаем подписчика в блоке transports - external_events, dsn указываем переменную окружения которую создали ранее для подключения к RabbitMQ,
- Задаем название обмена - user_events_exchange,
- Указываем тип - direct, это тип точного совпадения с ключом сообщения, есть еще типы, но для текущего примера нам этого достаточно,
- Задаем название очереди (user_login_queue) и привязанные к нему ключи (user_logged_in), в моем случае пока одно сообщения и соотвественно привязано только одно событие user_logged_in,
- В блоке routing привязываем конкретный класс события к подписчику.
Важный момент, при первом обращении Symfony автоматически проверяет наличие обмена и очереди, если их нет, то они создаются, но на проде как правило пользователь настроен так, что у него нет прав на создание обменов и очередей, для этого нужно запускать команду:
php bin/console messenger:setup-transports
Теперь что бы, отправить сообщение, нам необходимо внедрить зависимость с шиной команд в том месте где мы это ходим сделать, это может быть к примеру контроллер:
private MessageBusInterface $bus,
далее, просто делаем диспатч сообщения:
$this->bus->dispatch(new UserLoggedInEvent(
userId: $userId,
ipAddress: $request->getClientIp(),
createdAt: new \DateTimeImmutable(),
));
Этого достаточно для отправки сообщения, но если мы не запустим консьюмер то сообщение так и будет висеть в Rabbit не прочитанным, для того что бы прочитать сообщение, на нужно воспользоваться командой:
docker compose run --rm php-cli php bin/console messenger:consume external_events -vv
0 Сообщений