The problem with synchronous execution
In traditional PHP, code executes synchronously: each instruction waits for the previous one to finish. This becomes problematic when an operation takes several seconds:
<?php
public function sendNotification(User $user)
{
$this->emailService->sendWelcomeEmail($user); // 4 secondes
$this->smsService->sendConfirmation($user); // 2 seconde
$this->analytics->trackAction($user); // 1 seconde
// Total : 7 secondes d'attente pour l'utilisateur !
return $this->render('confirmation.html.twig');
}Result: The user waits in front of a loading screen.
To solve this problem, we can use “Symfony Messenger” to delay the execution of heavy scripts.
Setting up Symfony Messenger
Symfony Messenger is already well described in its official documentation. We will focus on the code part.
In the rest of this tutorial, you will find code snippets that you will need to adjust to your environment.
1- Create a Symfony Messenger handler
The handler is the class that contains the PHP code executed asynchronously. This is where you place the business logic that needs to run in the background.
<?php
namespace App\MessageHandler;
use App\Message\CheckMessageRead;
use App\Repository\MessageRepository;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Notifier\NotifierInterface;
Use Doctrine\ORM\EntityManagerInterface;
#[AsMessageHandler]
class CheckMessageReadHandler {
public function __construct(private MessageRepository $messageRepository, private NotifierInterface $notifier, private EntityManagerInterface $em) {
}
public function __invoke(CheckMessageRead $messageCheck): void {
// votre logique metier.
}
}2- Create the data container
This class is the “package” that carries the data needed for asynchronous execution. It contains all the information the Handler will need to do its job.
The Message is like an envelope containing instructions and data, while the Handler is the postal service that processes this envelope.
<?php
namespace App\Message;
class CheckMessageRead {
public function __construct(public readonly int $messageId, public readonly string $routeName) {
}
public function getMessageId() {
return $this->messageId;
}
public function getRouteName() {
return $this->routeName;
}
}3- Create the data container
php bin/console debug:messenger
/etc/systemd/system/
php bin/console cache:clear --env=prod
php bin/console cache:clear --env=dev
Reconstruit les caches :
php bin/console cache:warmup
php bin/console cache:warmup --env=prod