Retour sur le forum PHP 2024
Revivez les moments forts du Forum PHP 2024 avec l'AFUP ! Découvrez l'avenir du PHP et les innovations qui feront la différence.
Pour les connaisseurs des systèmes de messages, vous devez surement connaître Symfony/Messenger pour son système de file d'attente. Il permet notamment d'effectuer des scripts PHP en asynchrone. Le principe est simple, lorsqu'il y a un traitement à faire, plus long qu'un controller ne peut attendre, on place dans une file d'attente de traitement la tâche à effectuer, et ensuite vous avez ce que l'on appelle des Workers qui vont dépiler ces taches, et par exemple, faire des calculs lourds, envoyer des mails, transformer des PDF etc ...
Mais laissez-nous vous parler également de Enqueue, le système de PHP qui va plus loin. Dans cette article, nous allons donner des éléments de comparaison pour vous forger une idée.
Ces deux composants aident les applications à envoyer et recevoir des messages vers/depuis d'autres applications ou via des files d'attente de messages.
Tous les deux sont simples à installer sur votre projet, il suffit de faire le composer require et de l'inscrire dans le AppKernel.php, dans la liste de Bundle, donc ici pas de différence, je remets les lignes de commande que vous pouvez utiliser pour l'installer.
composer require enqueue/enqueue-bundle enqueue/fs
composer require symfony/messenger
Globalement, les deux systèmes ont les mêmes transports de disponible, alors il n'est pas forcément utile de tous les lister, mais vous avez AMQP, Kafka, MongoDb, Redis, SNS, SQS, Doctrine ...
PHP Enqueue fournit un outil de surveillance des files d'attente de messages, alors que Messenger non. Avec Enqueue, vous pouvez contrôler combien de messages ont été envoyés, combien ont été traités avec succès ou ont échoué. Combien de "Workers" travaillent, leur temps de disponibilité, les statistiques des messages traités, l'utilisation de la mémoire et la charge du système. L'outil peut être intégré à pratiquement n'importe quelle plate-forme d'analyse et de surveillance.
Il existe plusieurs intégrations : Datadog, Grafana... donc si vous souhaitez l'essayer ou même l'intégrer, vous trouverez la page d'installation ici.
Au delà de son aspect pratique, il existe des bordures à ne pas dépasser dans son utilisation. Car avec des gros volumes de messages à traiter, vous pouvez trouver quelques contraintes.
Par expérience, nous nous sommes trouvés à traiter quelques centaines de milliers de messages par jour dans un projet ou les messages étaient stockés dans doctrine (via une table messenger_messages), et comme le système ne dépilait pas assez, nous nous sommes dit: Augmentons le nombre de workers !!
Grave erreur, car la concurrence des accès en base de données est très compliquée pour Redis comme pour Doctrine/ Mysql.
Donc comment augmenter le depilage sans augmenter le nombre de Worker, nous avons tenté d'insérer des index sur les "queue_name" et "available_at" de la table messenger_messages, car en décortiquant la requête SQL, nous nous sommes apercus qu'il y avait un order by sur available_at.
Bonne Surprise, cela a fonctionné la pile diminuait, sauf que effet de bord, nous avons remarqué que nos workers s’arrêtaient régulièrement bien avant notre --time-limit configuré sur la commande. (Nous lancions des workers toutes les heures avec un time-limit de 3600 secondes, ce qui permettait de s'assurer qu'ils étaient killés tôt ou tard, tout en sachant qu'il y en avait forcément qui serait relancés).
En fait, en lançant le worker en verbose et à la main, nous avions une erreur "Deadlock found when trying to get lock; try restarting transaction", le mysql que nous avions 5.7 n’était pas capé pour avoir des insert/update/delete avec des index comme ceux que nous avions, il fallait passer en 8.0.
Le problème était que nous dépilions pourtant bien, mais juste cette erreur ralentissait le dépilage. Ce que nous avons fait est donc très simple?
Nous avons lancé dans notre crontab, des workers toutes les minutes avec une time-limit de 60 secondes, ainsi nous étions sûrs qu'il serait très souvent relancé malgré cette erreur, et que nous dépilerions rapidement nos listes de messages à traiter.
Pour aller plus loin, nous serions passés par Rabitmq qui nous stocke la donnée en NoSql sous son propre format, et qui permet d'aller plus vite dans le système de depilage puisque c'est un outil créé justement pour subir des insert/update/delete de manière concurrente sans bouger.
Bien entendu, si vous souhaitez aller plus loin, nous vous mettons à disposition des développeurs spécialisés sur Symfony qui sauront les intégrer dans vos projets. N'hésitez pas à nous contacter ici, ou à approfondir la documentation de Messenger et de Php Enqueue.
Découvrez également un autre composant Symfony : Swift Mailer !