Use Messenger to read queued message not sent with Messenger Use Messenger to read queued message not sent with Messenger symfony symfony

Use Messenger to read queued message not sent with Messenger


Ryan Weaver replied to a similar question on symfony's slack:

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


I did a quick implementation for my own needs, up to you to fit with your business logic :

1 - Create a Serializer wich implement the 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 - Retrieve the right Message using a factory :

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) Configure your new custom serializer for messenger :

framework:  messenger:    serializer: 'app.my_custom_serializer'

I'll try to go a bit further and find a way to "connect" a queue directly, will let you know.