change de nom...
Codéin, expert en développement Symfony, intègre API Platform dans ses projets. Sponsor de l'API Platform Conférence 2024 mais également participants, nous avons eu l'opportunité de suivre la plupart des conférences.
Cet événement, principalement destiné aux experts techniques, a brillé par la richesse de son contenu. Afin de vous faire revivre les moments forts des conférences, nous avons préparé une série d'articles pour vous offrir un condensé des points clés qui ont particulièrement attiré notre attention.
Dans ce second article, nous vous invitons à plonger au sein de la conférence de Frédéric Bouchery.
Frédéric Bouchery est expert PHP et lead chez CCM Benchmark
RabbitMQ est reconnu pour son efficacité dans l’orchestration des échanges des messages entre différentes applications, notamment dans le cadre de processus asynchrones. En plus de permettre la création de files d’attente et la répartition des tâches entre plusieurs travailleurs, ce système garantit une exécution fluide et une optimisation des ressources.
Dans cet article nous explorons ensemble les concepts de base de RabbitMQ et leur intégration avec Symfony Messenger et API platform.
Pour bien comprendre le fonctionnement de RabbitMQ, il est indispensable de maîtriser quelques termes clés, que Frédéric a brillamment expliqués :
Frédéric a particulièrement insisté sur le fait que l'exchange ne stocke pas les messages, mais joue un rôle clé dans leur direction vers les bonnes files d'attente selon des règles bien définies.
Dans RabbitMQ, une queue agit comme une file d'attente, stockant temporairement les messages avant qu'ils ne soient consommés. Ces messages, envoyés via un exchange, sont ensuite récupérés et traités par les consommateurs.
Frédéric a pris le temps de détailler certaines caractéristiques clés des queues, notamment :
Dans Symfony Messenger, il est possible de désactiver ces comportements par défaut de la manière suivante:
framework:
messenger:
transports:
async:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
queues:
default:
durable: true # Persiste après redémarrage
auto_delete: true # Supprimée quand il n’y a plus de consommateurs
Il est important de noter que les queues sont durables par défaut, ce qui signifie qu'elles survivent à un redémarrage du serveur RabbitMQ et les consommateurs peuvent reprendre le traitement.
Parfois, il arrive qu'un consommateur ne parvienne pas à traiter un message. Essayer à nouveau peut permettre d'éviter l'accumulation de messages non traités et aider à maintenir le système performant.
Différents statuts d'un message :
Pour gérer ces messages échoués, plusieurs options s'offrent à nous :
Stratégies pour gérer les retries :
Symfony Messenger : Gère les retries de manière abstraite et offre une flexibilité applicative avec des stratégies comme les délais croissants ou un nombre limité de tentatives. C'est idéal pour un contrôle fin des retries via l'application elle-même.
RabbitMQ seul : Nécessite une configuration spécifique avec les Dead Letter Exchanges (DLX), offrant un contrôle indépendant de l'application. C'est une solution adaptée pour gérer des retries directement via l'infrastructure.
Pour tirer parti de RabbitMQ avec Symfony Messenger et Api Platform, voici les étapes à suivre :
composer require symfony/messenger symfony/amqp-messenger
#[ApiResource(operations: [ new Post(messenger: true, output: false, status: 202) ])]
#[Entity]
final class Greeting
Par défaut, Symfony Messenger utilise un Fanout Exchange lorsqu'il est configuré pour fonctionner avec RabbitMQ. Cela signifie que tous les messages envoyés via l'exchange sont automatiquement distribués à toutes les queues liées, sans se soucier de la routing key. Voici un exemple de configuration :
framework:
messenger:
transports:
amqp_messages:
dsn: 'amqp://guest:guest@localhost:5672:%2f/messages'
routing:
'App\Message\Greeting': amqp_messages
<?php declare(strict_types=1);
namespace App\Decorator;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use App\Message\NotifyMessage;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\Messenger\MessageBusInterface;
#[AsDecorator('api_platform.doctrine.orm.state.persist_processor')]
readonly final class PersistProcessor implements ProcessorInterface
{
public function __construct(
private ProcessorInterface $decorated,
private MessageBusInterface $bus
) {}
public function process(mixed $data, Operation $operation, array $context = []): mixed
{
$entity = $this->decorated->process($data, $operation, $context);
$this->bus->dispatch(new NotifyMessage($entity->name));
return $entity;
}
}
framework:
messenger:
transports:
amqp_messages:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
serializer: 'App\Serializer\MessageSerializer
Lors du déploiement d'une nouvelle version, il est nécessaire de redémarrer les workers pour qu'ils prennent en compte le nouveau code. Cela peut se faire en exécutant la commande messenger:stop-workers, qui envoie un signal SIGTERM pour indiquer aux workers de terminer leurs tâches en cours avant de s'arrêter.
Dans des environnements distribués, un exchange spécifique peut également diffuser un message de shutdown pour coordonner l'arrêt des consommateurs sur plusieurs machines ou conteneurs sans avoir à les lister manuellement.
La conférence de FrédéricBouchery nous a donné une belle compréhension de RabbitMQ, tant comme outil autonome que dans son intégration avec Symfony Messenger et Api platfrom. En abordant les différents types d'éxchanges, et les mécanismes de gestion des retries, Frédéric a présenté des solutions robustes pour optimiser la gestion des messages. Cette flexibilité permet de concevoir des systèmes plus complexes et adaptés aux besoins spécifiques des environnements distribués.
Restez connectés pour découvrir nos prochains résumés sur les autres conférences de l'événement !