Josselin Dionisi - Freelance developer

Recurring actions? Symfony and RabbitMQ for asynchronous events...

ionicons-v5-k Josselin Dionisi Feb 13, 2024
206 reads Level: intermediate

Hello there! 😃 It's been a while since we've talked, because a lot happens behind the scenes in the life of a freelance developer. In fact, that's what we're going to talk about today, yes, behind the scenes stuff.

I'm going to introduce you to RabbitMQ, a tool that can be very easily coupled with Symfony and that really creates a formidable combo of performance and efficiency. I needed to implement it for a small home-made tool allowing me to schedule publications on social networks. 😁

What are messages and buses?

Before I get to the heart of the matter, I need to briefly explain what a message is.

"A message? Like a text message? But everyone can see what a message is in 2024!"

Well, yes, but not quite. Here we're talking about messages within Symfony's Messenger component.

In this context, messages can be anything from simple text strings to complex objects representing a task to be performed. They are then transported by a bus, which in turn acts as a distribution system, routing messages to the right recipients, called handlers.

How can RabbitMQ help optimize PHP scripts?

"Ok so we can send messages, but what's the point?"

Imagine you have a recurring task to perform that will contain several messages. Let's take a random example of a tool that would allow you to schedule publications on social networks.

So you might have 15 Instagram posts, 30 tweets, etc. to publish at 6pm for a multitude of different accounts.

The problem? It's likely to require a lot of resources, especially if the publications contain files to be uploaded, not to mention the number of API requests that can be more or less cumbersome.

If you're a seasoned developer, you'll know that PHP is a monothread language: it processes everything at once in the order in which its code is executed.

This is exactly where RabbitMQ comes into its own, as you can delegate these tasks asynchronously. One will be independent of the other, so your publications won't be blocked when a heavier one is being processed. Do you follow?

How do I set up a RabbitMQ instance?

"It sounds interesting, but it's complicated to set up, I imagine?"

Well, not at all! 😊

In fact, Symfony already includes Message Queuing (yes, that's the right name for it) with RabbitMq. If you follow the documentation in the previous link, you'll easily be able to connect the two. As always, I recommend running a Docker container for RabbitMQ, for simplicity's sake. You'll also need to activate PHP's AMQP extension .

Once the two are connected, you'll need to create 2 classes in Symfony. One will correspond to the message you wish to send. Like a Symfony Entity, you can add attributes and functions to retrieve them elsewhere.

When you launch your publication script, you'll create a message object of the same type as this class, e.g. Publication.

Then you'll need a handler class to manage these messages and know what to do with them. For us, the aim here would be to make our calls to the API and all the heavy tasks required by our application. This is the part that will be sent and delegated to RabbitMQ.

"Ok great I've got my two classes and I manage to get them working, but then what do I do?"

Well, if everything's set up correctly, you shouldn't have to do anything except run the commands for your script and then for RabbitMQ to actually start taking care of it, which is called "consuming the messages" and translates into this Symfony command: bin/console messenger:consume async

How can I track the RabbitMQ process and the messages consumed?

There's a RabbitMQ plugin called Management that does just that, giving you a graphical interface for tracking what's going on in your message manager. Here are a few examples:

RabbitMQ's dashboard

Here we can see that an instance is waiting with the status "ready". It needs the messenger:consume command to be launched before it can be executed.

Symfony command : Messenger;consume

The post has now been published

Automatically published tweet

Our publication is now online! 😀

Conclusion: The art of good communication

In short, Symfony's Messaging component is your ally in turning message management into a pleasure rather than a headache. Combine it with RabbitMQ and you have a robust, flexible and high-performance solution for managing your application's asynchronous communications.

However, be sure to follow the documentation carefully before implementing it, as you'll probably need to have tools on your server to monitor processes, cut off commands at certain times, etc.

Now you've got everything you need to take your application to the next level 😊