Используйте Messenger для чтения сообщений в очереди, отправленных не с помощью Messenger

Я пытаюсь прочитать сообщение в очереди (в RabbitMQ), которое не было отправлено с помощью Symfony Messenger. Кажется, что Messenger добавляет некоторые заголовки, например

headers: 
    type: App\Message\Transaction

но при чтении внешних сообщений этого заголовка не существует.

Итак, есть ли способ сообщить Messenger, что каждое сообщение в очереди A должно рассматриваться как тип сообщения Transaction?

Что у меня есть сегодня:

framework:
    messenger:
        transports:
            # Uncomment the following line to enable a transport named "amqp"
            amqp:
                dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
                options:
                    exchange:
                        name: messages
                        type: direct
                    queue:
                        name: queue_messages

        routing:
            # Route your messages to the transports
             'App\Message\Transaction': amqp

и что я хотел бы добавить, это что-то вроде:

        routing:
            # Route your messages to the transports
             amqp: 'App\Message\Transaction'

На самом деле это не решение, но если у вас есть контроль над созданием сообщения, вы можете иметь заголовок type со значением FQCN. Я был бы признателен за лучшее решение, подобное описанному в вашем посте.

Erwan Haquet 09.04.2019 09:23

Я был недостаточно ясен. Дело в том, что я не контролирую создание сообщения, я знаю только то, что будет отправлено в этой очереди.

Kevin Pires 09.04.2019 09:36

Согласитесь, непонятное и на самом деле не жизнеспособное решение. Спросите в symfony slack, можно ли реализовать такую ​​конфигурацию или фабрику, я вернусь к вам.

Erwan Haquet 09.04.2019 12:02
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
7
3
2 223
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Райан Уивер ответил на аналогичный вопрос в Slack Symfony.:

You will need a custom serializer for messenger if the messages do not originate from messenger :)

1) You create a custom serialize (implements SerializerInterface from Messenger) and configure it under the messenger config

2) Somehow in that serializer, you take JSON and turn it into some "message" object you have in your code. How you do that is up to you - you need to somehow be able to look at your JSON and figure out which message class it should be mapped to. You could then create that object manually and populate the data, or use Symfony's serializer. Wrap this in an Envelope before returning it

3) Because your serializer is now returning a "message" object if some sort, Messenger uses its normal logic to find the handler(s) for that Message and execute them


Я сделал быструю реализацию для своих нужд, чтобы вы соответствовали вашей бизнес-логике. :

1 - Создайте Serializer, который реализует SerializerInterface:


   // I keeped the default serializer, and just override his decode method.

   /**
     * {@inheritdoc}
     */
    public function decode(array $encodedEnvelope): Envelope
    {
        if (empty($encodedEnvelope['body']) || empty($encodedEnvelope['headers'])) {
            throw new InvalidArgumentException('Encoded envelope should have at least a "body" and some "headers".');
        }

        if (empty($encodedEnvelope['headers']['action'])) {
            throw new InvalidArgumentException('Encoded envelope does not have an "action" header.');
        }

        // Call a factory to return the Message Class associate with the action
        if (!$messageClass = $this->messageFactory->getMessageClass($encodedEnvelope['headers']['action'])) {
            throw new InvalidArgumentException(sprintf('"%s" is not a valid action.', $encodedEnvelope['headers']['action']));
        }

        // ... keep the default Serializer logic

        return new Envelope($message, ...$stamps);
    }

2 - Получить право Message с помощью фабрики:

class MessageFactory
{
    /**
     * @param string $action
     * @return string|null
     */
    public function getMessageClass(string $action)
    {
        switch($action){
            case ActionConstants::POST_MESSAGE :
                return PostMessage::class ;
            default:
                return null;
        }
    }
}

3) Настройте свой новый пользовательский сериализатор для мессенджера:

framework:
  messenger:
    serializer: 'app.my_custom_serializer'

Я попытаюсь пойти немного дальше и найти способ «подключить» очередь напрямую, дам вам знать.

Другие вопросы по теме