How to use Symfony Messenger with Pimcore?
What is Symfony Messenger?
Symfony Messenger is a component that helps applications manage queues, especially when communicating with other systems or delegating work to different services. Since Pimcore replaced all existing asynchronous queues with Symfony Messenger, it's even easier to implement it in your project.
Use case in real life
Let's say that there is a competition form on your website, even very simple one with three fields:
- firstname
- message
The controller handles the contact form, saves the object in the database, and sends an e-mail with accurate data.
Well, this already works fine, but is there an even better way?
Where is the problem?
Before the implementation of Symfony Messenger, processing the contact form, saving the object, and sending an e-mail took about 4 seconds.
Why? The main reason is communication with the SMTP server responsible for sending e-mails. There is a huge difference in processing time when skipping this part and just saving the object. The difference is noticeable and can affect how users experience the website's performance and usability.
Magic of queues
This is precisely why Symfony Messenger was created, and Pimcore replaced its existing asynchronous queues. Two classes have to be created:
- CompetitionApplicationMessage, which stores data, CompetitionApplication in this case
- CompetitionApplicationMessageHandler, which in this case is responsible for saving the object and sending the e-mail.
Now, in the controller, instead of executing the saving object and sending an e-mail, call CompetitionApplicationMessage by injecting the MessageBusInterface into the method responsible for handling requests. Again, remember to change your services.yaml configuration and tell your handler that it is a message handler now.
It's very exciting. But there is a big disappointment because the form is still processing for about 4 seconds.
Asynchronicity is the key
By default, Symfony Messenger executes tasks immediately. To make it asynchronous, you have to create config/packages/messenger.yaml configuration file with a definition of how the Message should be executed and handled. MESSENGER_TRANSPORT_DSN environmental variable indicates which transporter will be responsible for queues. It can be redis, RabbitMQ, or even a database. For queue tasks to execute correctly using cron or supervisord cyclically, the command php bin/console messenger:consume async must be run.
Results
By processing our form asynchronously with Symfony Messenger, we can see a significant increase in performance.
Also, using a system to control processes such as supervisord, the logic executed within our task is charged to the service responsible for handling the processes, rather than the application, which with high traffic and a large number of processes can give a gigantic increase in perceived performance and stability.
Another advantage is that in a situation where the SMTP service is unavailable, the task will not be marked as completed, and there will be three attempts to restart it. If the logic remained in the controller and the email was not sent correctly, there would never be a retry. According to the Messenger configuration, the number of retry attempts and the intervals between them can be managed.
Resources
Looking to gain more Pimcore knowledge? The training platform Pimcore Academy offers on-demand video courses about many Pimcore topics. The content is focused on software developers. It includes code samples, tutorials, and links to further information. Prove your expertise and earn 3 official certificates. Start learning to maximize your Pimcore know-how.