How to setup Symfony Messenger in 5 minutes

Edouard Courty
4 min readNov 7, 2022

--

Symfony Messenger is a bundle that provides everything that’s needed to consume messages coming from a message queue.

If you don’t know what message queuing is, you can check out this article to better understand its ins and outs.

I’ll speak about

Introduction & Installation

Messenger can consume messages from different transport types:

  • AMQP services (like RabbitMQ)
  • Doctrine (storing messages in an SQL table)
  • Cache systems (like Redis)

To begin with, install the package by running the following command:

composer require symfony/messenger

Messenger works with Messages and Message Handlers.

Messages will be published to the message queue, and handlers will consume them.

Messages & Handlers

Let’s create our first message!

The example we’ll use is sending an email validation to a user who just created an account on our website.

The User entity has three fields, username, email_address, and password.

A message should contain any values that are needed to be able to further consume the message.

In our case, we just need the User ID to be able to retrieve the user into the message handler and therefore email this user.

SendRegistrationEmailMessage.php

Our message can now be created, let’s write our handler.

Quick explanation of what’s happening here:

Symfony Messenger comes with a PHP Attribute #[AsMessageHandler] that can be declared on the class, which tells Symfony that this service needs to be considered as a message handler and route the correct messages to it.

If you’re not using PHP 8 or don’t want to use PHP Attributes, you can simply implement the MessageHandlerInterface on your message handler, and you’re good to go.

The type of the to-be-consumed message is the one that is declared in the __invoke method.

This means that for each message we create, we need to create a message handler, with the correct type in the __invoke method and the routing will be automatically handled by Symfony.

Message handlers are normal Symfony services, you can use the dependency injection mechanism as usual.

Message transportation & routing

We are now able to create and consume messages, but what about storing them somewhere?

We spoke about RabbitMQ, Redis and Doctrine earlier. Let’s dive into the networking part of this Story.

First, if you’re going to use an AMQP protocol like RabbitMQ, you need to install the symfony/amqp-messenger package.

composer require symfony/amqp-messenger

If you’re going to use Doctrine, install the following instead:

composer require symfony/doctrine-messenger

Last, if you want to use Redis for your transport, this is the package you need to install:

composer require symfony/redis-messenger

I’ll focus on RabbitMQ since it’s the most used queue protocol.

Installing Symfony Messenger will created 3 entries in your .env file.

# MESSENGER_TRANSPORT_DSN=amqp://user:pass@host:port/%2f/messages
# MESSENGER_TRANSPORT_DSN=doctrine://default
# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages

Uncomment the one you need to use (AMQP / Doctrine / Redis) and fill it with your credentials.

Here is a link to the documentation if you want to know more about the other transports.

Symfony Messenger comes with a configuration file named messenger.yaml that you’ll find in the config/packages directory.

Here is what your configuration file should look like:

The transport key will hold all the configuration regarding the handling (consuming) of the messages.

The failure_transport key holds the name of the transport that needs to be used in case of a failure (Exception thrown during handling).

There are some cases where you want to retry a message if it fails: that’s what the retry_strategy is for.

Each transport is mapped to an exchange that put the messages in a queue, transports are Symfony Messenger related when queues are RabbitMQ related.

You can name your transport “foo” and its queue “bar”, it doesn’t matter.

Finally, the routing part explains how to route a given message instance to transport.

In our case, we want to map the App\Message\SendRegistrationEmailMessage message to the registration_email transport.

In case you want to route different messages to the same transport, you can use interfaces that are implemented by the message class instead of the class names.

This configuration can be used as a solid base for your project.

It can be tweaked a little, but it would be too long to expand on everything here, so I’ll leave a link to the official documentation.

Message publishing

Publishing a message is done using the MessageBus service, provided by Symfony Messenger.

Here is an example of how it’s done:

I hope this story helped you understand the ins and outs of message handling with the Symfony Messenger package.

If you liked this content, feel free to check out my other stories and follow my account to support me.

Have a good day!

--

--

Edouard Courty

Web Developer & IT Teacher based in Paris - Back-end guru - Co-founder of @IMXrarity