L'exécution de tâches lourdes de manière synchrone est l'un des principaux freins à la performance des applications web modernes. Qu'il s'agisse de l'envoi d'e-mails, du traitement d'images ou de la communication avec des API tierces, ces opérations ne devraient pas bloquer la réponse HTTP envoyée à l'utilisateur. Enqueue offre une solution robuste et normalisée (basée sur PSR) pour gérer les files d'attente de messages au sein de l'écosystème PHP, s'intégrant parfaitement au framework Symfony.
Avantages de l'approche asynchrone
- Fluidité de l'expérience utilisateur : La réponse est envoyée immédiatement tandis que le traitement se poursuit en arrière-plan.
- Résilience du système : En cas de panne d'un service externe, le message reste dans la file d'attente pour être rejoué ultérieurement.
- Scalabilité : Possibilité de multiplier les instances de consommateurs (workers) pour absorber une charge de travail croissante.
Installation et configuration initiale
Pour débuter avec Enqueue dans un projet Symfony, installez le bundle ainsi que l'adaptateur de transport de votre choix. Dans cet exemple, nous utiliserons l'extension AMQP pour communiquer avec RabbitMQ :
composer require enqueue/enqueue-bundle enqueue/amqp-lib
Ensuite, définissez la connexion dans votre fichier de configuraton config/packages/enqueue.yaml :
enqueue:
default:
transport:
dsn: "amqp://user:password@localhost:5672/%2f"
client: ~
Production de messages
Pour envoyer une tâche dans la file d'attente, injectez l'interface ProducerInterface dans votre service ou contrôleur. Voici comment initier un traitement asynchrone après la création d'une commande :
// src/Controller/OrderController.php
namespace App\Controller;
use Enqueue\Client\ProducerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
class OrderController extends AbstractController
{
public function checkout(ProducerInterface $queueProducer): Response
{
// Logique métier pour créer la commande...
$orderData = ['id' => 1234, 'email' => 'client@example.com'];
// Envoi du message vers le sujet 'confirm_order'
$queueProducer->sendEvent('confirm_order', json_encode($orderData));
return new Response('Commande enregistrée, traitement en cours...');
}
}
Consommation et traitement des messages
Le consommateur est la classe chargée d'extraire le message de la file et d'exécuter la logique associée. Il doit implémenter Processor et, idéalement, TopicSubscriberInterface pour un routage automatique.
// src/Consumer/OrderConfirmationHandler.php
namespace App\Consumer;
use Enqueue\Client\TopicSubscriberInterface;
use Interop\Queue\Context;
use Interop\Queue\Message;
use Interop\Queue\Processor;
class OrderConfirmationHandler implements Processor, TopicSubscriberInterface
{
public function process(Message $msg, Context $ctx): string
{
$payload = json_decode($msg->getBody(), true);
// Simulation d'un traitement long (ex: génération de facture PDF)
// logic_generate_pdf($payload['id']);
return self::ACK; // Accusé de réception : le message est supprimé de la file
}
public static function getSubscribedTopics(): array
{
return ['confirm_order'];
}
}
Pour lancer le processus d'écoute, utilisez la commande console fournie par le bundle :
php bin/console enqueue:consume --setup-broker
Gestion avancée et robustesse
Dans un environnement de production, il est crucial d'assurer la continuité du service et l'intégrité des données.
Idempotence des traitements
Un message peut parfois être délivré plusieurs fois suite à un incident réseau. Votre logique de traitement doit vérifier si l'action n'a pas déjà été effectuée :
public function process(Message $msg, Context $ctx): string
{
$orderId = json_decode($msg->getBody())->id;
if ($this->repository->isAlreadyProcessed($orderId)) {
return self::ACK;
}
// Traitement...
return self::ACK;
}
Supervision des processus
Pour garantir que vos consommateurs tournent en permanence, l'utilisation d'un gestionnaire de processus comme Supervisor est recommandée. Voici un exemple de configuration simple :
[program:symfony_worker]
command=php /var/www/html/bin/console enqueue:consume --env=prod
autostart=true
autorestart=true
user=www-data
numprocs=2
stdout_logfile=/var/log/worker.out.log
Enqueue s'intègre également au Profiler de Symfony, permetant de visualiser en phase de développement le nombre de messages envoyés et le temps de traitement de chaque processeur directement depuis la barre d'outils de debug.