Hébergement site web Tunisie , serveur vps cloud – Zenhosting

final-logo

Découvrez nos offres d'hébergement Cloud

Hébergement Web Simple, rapide et sécurisé. Confiez-nous l’hébergement de votre site web dès maintenant.

hébergement web

Traitements Asynchrones avec Symfony

symfony+messenger

Depuis sa version 4.1, Symfony intègre le composant Messenger. Ce composant facilite grandement les traitements asynchrones qui permettent, par exemple, d’assurer des gros volumes de traitements tout en garantissant un temps de réponse instantané à l’utilisateur.

Le cas d’usage

Imaginons qu’un utilisateur historique d’une boutique en ligne souhaite recevoir une archive contenant toutes ses factures (environ 1000). La plupart des factures doivent être créées en PDF, ajoutées à l’archive et cette dernière doit être envoyée par mail en fin de traitement.

symfony+messenger

En effet, les serveurs HTTP ne sont pas conçus pour attendre de manière indéfinie que le traitement d’une requête se termine. Outre l’engorgement réseau et le blocage de la machine que cela engendre, nous devons attendre la fin du traitement pour répondre à l’utilisateur, ce qui serait complètement inacceptable (plusieurs secondes voire minutes). Imaginons en plus qu’une centaine d’utilisateurs font la même demande en même temps et nous pouvons dire au-revoir à notre serveur.

Quelles sont les solutions dans ce cas ?

Les Threads

PHP ne bénéficie pas sur support des Threads comme peuvent le faire nativement Java ou ASP. En plus, les Threads permettent bien de “sous-traiter” des tâches mais impliquent souvent une gestion assez fine derrière pour éviter de surcharger la machine… Ce n’est donc pas l’idéal dans notre cas non plus.

API Node.js

Pourquoi pas ! En plus on peut facilement scaler la chose en multipliant les serveurs pour répondre à de plus en plus de demandes ! “Oui mais”… Deux problèmes majeurs se posent alors : notre code est dupliqué à deux endroits (pour la récupération du client et de ses factures), et notre portefeuille est rarement aussi “scalable” que notre hébergeur…

On fait comment alors

Tous les héros ne portent pas forcément de cape : c’est là que le composant Symfony Messenger vient à notre secours ! Ce composant apporte une couche d’abstraction très confortable au développeur autour du concept apporté par les “Messages Brokers”. L’idée est d’envoyer un “Message” dans une file d’attente, qui sera consommé par un Worker (dit Handler).

Dans notre cas, c’est l’outil idéal et ce pour plusieurs raisons:

  • Évite la surcharge de la machine: un Worker travaille unitairement, donc tant qu’il n’a pas fini sa tâche, les autres messages restent en file d’attente.
  • Scalable à souhait : beaucoup de Message Brokers sont disponibles sur le marché – RabbitMQ, ActiveMQ ou AWS SQS pour ne citer que les plus connus, avec beaucoup de choix d’architecture possible, failover, etc.
  • Le Message et le Worker sont codés au même endroit : au sein de notre application Symfony ! Tout est donc accessible ET testable: services, repositories, entités…

Il ne nous reste plus qu’à adapter le message pour notre utilisateur, et nous pouvons coder. Voici à quoi va ressembler le scénario final:

  1. Utilisateur HTTP GET /invoices/archive
  2. Serveur envoie un message en file d’attente: “Générer archive pour client #42”
  3. L’utilisateur voit une page lui indiquant que son archive va lui être envoyée par mail prochainement.

Et voilà ! Notre Worker prendra le relais dès qu’il recevra le message, constituera l’archive et l’enverra par mail une fois terminée. Voyons maintenant comment implémenter tout ça dans notre application…

Le Message

Notre Worker n’aura besoin que de l’ID de l’utilisateur afin de générer l’archive. Il est généralement conseillé de créer des messages les plus légers possibles car ils seront sérialisés pour le transport dans la file d’attente.

<?php
namespace App\Message;

class CreateArchiveMessage
{
    public $userId;

    public function __construct(int $userId)
    {
        $this->userId = $userId;
    }
}


Le Worker

Nous allons maintenant créer le Worker qui fera le plus gros du travail.

<?php
namespace App\MessageHandler;

use App\Message\CreateArchiveMessage;
use Symfony\Component\Messenger\Handler\MessageHandlerInterface;

class CreateArchiveHandler implements MessageHandlerInterface
{
    // use constructor + autowiring to inject required services

    public function __invoke(CreateArchiveMessage $message)
    {
        // SELECT * FROM invoices WHERE user_id = $message->userId
        // Create PDFs + add to archive
        // send archive by mail
    }
}

Le Dispatch

Maintenant que notre Message et son Handler sont prêts, nous allons pouvoir faire fonctionner tout ça très simplement directement dans notre Controller:

<?php
namespace App\Controller;

use App\Message\CreateArchiveMessage;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Messenger\MessageBusInterface;

class CreateArchiveController extends AbstractController
{
    public function index(MessageBusInterface $bus)
    {
        $bus->dispatch(new CreateArchiveMessage($user->getId()));
    }
}

Tada! Vous pouvez déjà tester votre code, sans rien faire de plus.

Le Transport

Plusieurs Transports existent par défaut. Il est bien sûr possible de créer son propre Transport si nécessaire. Celui qui nous sera utile ici sera le transport générique “AMQP” qui fonctionne avec la plupart des Message Brokers que nous avons cités :

# config/packages/messenger.yaml
framework:
    messenger:
        transports:
            amqp: "amqp://guest:guest@localhost:5672/%2f/messages"

Il nous reste à lancer le démon qui permet de traiter les messages en file d’attente, et voilà : notre application Symfony est maintenant prête à faire de l’asynchrone !

php bin/console messenger:consume-messages amqp

En production, ce démon devra être lancé par un superviseur pour qu’il soit relancé/monitoré en cas de crash (supervisor par exemple). Une fois lancé, il tourne avec le code déployé à ce moment-là. Il faudra donc penser à le redémarrer après chaque déploiement de l’application.

Le Routing

Le composant Messenger donne également la possibilité de router chaque Message vers des Broker différents. Ce besoin peut arriver si par exemple nous souhaitons envoyer les emails depuis un autre serveur. Nous enverrons alors depuis notre CreateArchiveHandler un nouveau Message qui se chargera d’envoyer le message et transitera dans un Transport différent.

# config/packages/messenger.yaml
framework:
    messenger:
        routing:
            'App\Message\CreateArchiveMessage': amqp
            'App\Message\SendEmailMessage': amqp_email
Cet Article est utile ? Votez
0 / 5 5

Your page rank:

Facebook
Twitter
LinkedIn
Pinterest

Plus à explorer

seo image
Seo

Comment améliorer l’impact SEO de vos images ?

L’utilisation d’images sur les sites Web est très courante. Cependant, tout comme il est important de sélectionner les images appropriées, il est important de sélectionner

 20% Réduction

Bénéficiez de 20 % de réduction pour votre 1 achat
Confirmer
*Offre valable uniquement pour les nouveaux inscrits
close-link

Mailsuite fonctionne sur Tous vos appareils

Prenez votre communication avec vous en installant des applications complètes sur votre appareil Android, iOS windows et MacOs

Mailsuite fonctionne sur Tous vos appareils

Prenez votre communication avec vous en installant des applications complètes sur votre appareil Android, iOS windows et MacOs