window.pipedriveLeadboosterConfig = { base : 'leadbooster-chat.pipedrive.com', companyId : 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version : 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster existe déjà') } else { w.LeadBooster = { q : [], on : function (n, h) { this.q.push({ t : 'o', n : n, h : h }) }, trigger : function (n) { this.q.push({ t : 't', n : n }) }, } } })() Symfony : Microservices Communication part I - The Codest
The Codest
  • A propos de nous
  • Services
    • Développement de logiciels
      • Développement frontal
      • Développement backend
    • Staff Augmentation
      • Développeurs frontaux
      • Développeurs backend
      • Ingénieurs des données
      • Ingénieurs en informatique dématérialisée
      • Ingénieurs AQ
      • Autres
    • Conseil consultatif
      • Audit et conseil
  • Industries
    • Fintech et banque
    • E-commerce
    • Adtech
    • Santé (Healthtech)
    • Fabrication
    • Logistique
    • Automobile
    • IOT
  • Valeur pour
    • CEO
    • CTO
    • Gestionnaire des livraisons
  • Notre équipe
  • Études de cas
  • Savoir comment
    • Blog
    • Rencontres
    • Webinaires
    • Ressources
Carrières Prendre contact
  • A propos de nous
  • Services
    • Développement de logiciels
      • Développement frontal
      • Développement backend
    • Staff Augmentation
      • Développeurs frontaux
      • Développeurs backend
      • Ingénieurs des données
      • Ingénieurs en informatique dématérialisée
      • Ingénieurs AQ
      • Autres
    • Conseil consultatif
      • Audit et conseil
  • Valeur pour
    • CEO
    • CTO
    • Gestionnaire des livraisons
  • Notre équipe
  • Études de cas
  • Savoir comment
    • Blog
    • Rencontres
    • Webinaires
    • Ressources
Carrières Prendre contact
Flèche arrière RETOUR
2022-06-28
Développement de logiciels

Symfony : Microservices Communication partie I

The Codest

Sebastian Luczak

PHP Chef d'unité

Lisez la première partie de notre série PHP consacrée à la communication entre microservices dans le framework Symfony et à la manière la plus populaire - la communication AMQP en utilisant RabbitMQ.

L'architecture moderne des applications a obligé les développeurs à changer leur façon de concevoir la communication entre les différents composants des systèmes informatiques. Autrefois, les choses étaient plus simples : la plupart des systèmes étaient créés sous la forme de structures monolithiques reliées entre elles par un réseau de connexions logiques. Le maintien de ces dépendances dans une PHP projet a été un défi de taille pour Développeurs PHPL'utilisation de la technologie de l'information, la popularité croissante des solutions SaaS et l'augmentation considérable de la popularité de la technologie nuage Les services de la Commission européenne ont fait en sorte qu'aujourd'hui, nous entendons de plus en plus parler de microservices et de modularité des applications.

Comment, en créant des microservices indépendants, faire en sorte qu'ils échangent des informations entre eux ?

Cet article est le premier d'une série de billets sur communication microservices dans Symfony et couvre le moyen le plus populaire - la communication AMQP à l'aide de RabbitMQ.

Objectif

Créer deux applications indépendantes et assurer la communication entre elles en utilisant uniquement le bus de messages.

Le concept

Nous avons deux applications imaginaires et indépendantes :
* app1Le système d'information sur la santé : qui envoie des notifications par courrier électronique et par SMS aux employés
* app2Le système de gestion des ressources humaines : il vous permet de gérer le travail de vos employés et de leur assigner des tâches.

Nous voulons créer un système moderne et simple qui permette d'attribuer un travail à un employé dans le cadre d'un contrat de travail. app2 enverra une notification au client en utilisant app1. Malgré les apparences, c'est très simple !

Préparation

Pour les besoins de cet article, nous utiliserons la dernière version de Symfony (version 6.1 au moment de la rédaction) et la dernière version de PHP (8.1). En quelques étapes très simples, nous allons créer un environnement Docker local fonctionnel avec deux microservices. Tout ce dont vous avez besoin est :
* un ordinateur en état de marche,
* Docker + installé Environnement Docker Compose
* et d'un CLI Symfony et du temps libre.

Environnement d'exécution

Nous utiliserons les capacités de Docker en tant qu'outil de virtualisation et de conteneurisation d'applications. Commençons par créer une arborescence de répertoires, un cadre pour deux applications. Applications Symfonyet décrire l'infrastructure de nos environnements à l'aide de l'outil docker-compose.yml fichier.

 cd ~
 mkdir microservices-in-symfony
 cd microservices-in-symfony
 symfony new app1
 symfony new app2
 touch docker-compose.yml

Nous avons créé deux répertoires pour deux applications Symfony distinctes et créé un répertoire vide docker-compose.yml pour lancer notre environnement.

Ajoutons les sections suivantes au docker-compose.yml file:

version : '3.8'

services :
app1 :
nom d'utilisateur : app1
build : app1/.
restart : on-failure
envfile : app1/.env
environnement :
APPNAME : app1
tty : true
stdinopen : true

app2 :
nom d'utilisateur : app2
build : app2/.
restart : on-failure
envfile : app2/.env
environnement :
APPNAME : app2
tty : true
stdinopen : true

rabbitmq :
nom d'utilisateur : rabbitmq
image : rabbitmq:management
ports :
- 15672:15672
- 5672:5672
environnement :
- RABBITMQDEFAULTUSER=utilisateur
- RABBITMQDEFAULT_PASS=mot de passe

Source code disponible directement : thecodest-co/microservices-in-symfony/blob/main/docker-compose.yml

Mais attendez, que s'est-il passé ici ? Pour ceux qui ne connaissent pas Docker, le fichier de configuration ci-dessus peut sembler énigmatique, mais son objectif est très simple. En utilisant Docker Compose, nous construisons trois "services" :

  • app1 : qui est un conteneur pour la première application Symfony
  • app2 : qui est le conteneur pour la deuxième application Symfony
  • rabbitmq : l'image de l'application RabbitMQ en tant que couche intermédiaire de communication

Pour un fonctionnement correct, nous avons encore besoin de Fichier Docker qui sont la source pour construire les images. Nous allons donc les créer :

 touch app1/Dockerfile
 touch app2/Dockerfile

Les deux fichiers ont exactement la même structure et se présentent comme suit :

Depuis php:8.1

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPY . /app/
WORKDIR /app/

ADD https://github.com/mlocati/docker-php-extension-installer/releases/latest/download/install-php-extensions /usr/local/bin/

RUN chmod +x /usr/local/bin/install-php-extensions && sync &&
install-php-extensions amqp

Exécuter apt-get update
&& apt-get install -y libzip-dev wget --no-install-recommends
&& apt-get clean
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

Exécuter docker-php-ext-install zip ;

CMD bash -c "cd /app && composer install && php -a"

Le code source est disponible directement : /thecodest-co/microservices-in-symfony/blob/main/app1/Dockerfile

Le fichier ci-dessus est utilisé par Docker Compose pour construire un conteneur à partir d'une image PHP 8.1 avec Composer et l'extension AMQP installée. De plus, il exécute l'interpréteur PHP en mode append pour que le conteneur continue à fonctionner en arrière-plan.

Votre arborescence de répertoires et de fichiers devrait maintenant ressembler à ce qui suit :

 .
 ├── app1
 │ └── Dockerfile
 | (...) # Symfony App Structure
 ├── app2
 │ └── Dockerfile
 | (...) # Symfony App Structure
 └── docker-compose.yml

Le premier microservice Symfony

Commençons par le app1 et la première application.
Dans notre exemple, il s'agit d'une application qui écoute et consomme les messages de la file d'attente envoyée par app2 comme décrit dans les exigences :

l'attribution d'une tâche à un travailleur dans app2 enverra une notification au client

Commençons par ajouter les bibliothèques nécessaires. AMQP est supporté nativement pour la bibliothèque symfony/messenger l'extension. Nous installerons également monologue/monologue pour garder une trace des journaux système afin de faciliter l'analyse du comportement des applications.

 cd app1/
 symfony composer req amqp ampq-messenger monolog

Après l'installation, un fichier supplémentaire a été ajouté sous config/packages/messenger.yaml. Il s'agit d'un fichier de configuration pour le composant Symfony Messenger et nous n'avons pas besoin de son contenu. configuration complète.
Remplacez-le par le fichier YAML ci-dessous :

cadre :
messager :
# Décommentez ceci (et le transport failed ci-dessous) pour envoyer les messages échoués à ce transport en vue d'un traitement ultérieur.
# failure_transport : failed

    transports :
        # https://symfony.com/doc/current/messenger.html#transport-configuration
        external_messages :
            dsn : '%env(MESSENGER_TRANSPORT_DSN)%'
            options :
                auto_setup : false
                exchange :
                    name : messages
                    type : direct
                    default_publish_routing_key : from_external
                queues :
                    messages :
                        binding_keys : [from_external]

Le code source est disponible directement : thecodest-co/microservices-in-symfony/blob/main/app1/config/packages/messenger.yaml

Symfony Messenger est utilisé pour la communication synchrone et asynchrone dans les applications Symfony. Il supporte une variété de transportsou sources de vérité de la couche transport. Dans notre exemple, nous utilisons l'extension AMQP qui prend en charge le système de file d'attente d'événements RabbitMQ.

La configuration ci-dessus définit un nouveau transport nommé messages_externesqui fait référence à la MESSENGER_TRANSPORT_DSN et définit l'écoute directe sur le serveur messages dans le bus de messages. À ce stade, modifiez également le app1/.env et ajouter l'adresse de transport appropriée.

"`env

(...)
MESSENGERTRANSPORTDSN=amqp://user:password@rabbitmq:5672//messages
(...)
"
Après avoir préparé le cadre d'application et configuré les bibliothèques, il est temps d'implémenter la logique d'entreprise. Nous savons que notre application doit répondre à l'attribution d'un travail à un employé. Nous savons également que l'affectation d'un travail dans le systèmeapp2 modifie le statut du travail. Nous allons donc créer un modèle qui imite le changement de statut et le sauvegarder dans le cheminapp1/Message/StatusUpdate.php` :
image
 {
public function __construct(protected string $status){}

public function getStatus() : string
{
    return $this->status ;
}

}

Le code source est disponible directement : /thecodest-co/microservices-in-symfony/blob/main/app1/src/Message/StatusUpdate.php

Nous avons toujours besoin d'une classe qui implémentera la logique métier lorsque notre microservice recevra l'événement ci-dessus de la file d'attente. Créons donc une classe Gestionnaire de messages dans le app1/Handler/StatusUpdateHandler.php chemin :

image
 use PsrLogLoggerInterface ;
use SymfonyComponentMessengerAttributeAsMessageHandler ;

[AsMessageHandler]

classe StatusUpdateHandler
{
public function __construct(
protected LoggerInterface $logger,
) {}

public function __invoke(StatusUpdate $statusUpdate) : void
{
    $statusDescription = $statusUpdate->getStatus() ;

    $this->logger->warning('APP1 : {STATUS_UPDATE} - '.$statusDescription) ;

    // le reste de la logique commerciale, c'est-à-dire l'envoi de l'email à l'utilisateur
    // $this->emailService->email()
}

}

Le code source est disponible directement : /thecodest-co/microservices-in-symfony/blob/main/app1/src/Handler/StatusUpdateHandler.php

PHP rendent les choses beaucoup plus faciles et signifient que dans ce cas particulier, nous n'avons pas à nous soucier de l'autowiring ou de la déclaration de service. Notre microservice pour gérer les événements du domaine est prêt, il est temps de passer à la deuxième application.

Deuxième microservice Symfony

Nous allons examiner les app2 et le second Application Symfony. Notre idée est d'envoyer un message à la file d'attente lorsqu'un travailleur se voit assigner une tâche dans le système. Nous allons donc configurer rapidement AMQP et faire en sorte que notre deuxième microservice commence à publier des messages Mise à jour de l'état au bus de messages.

L'installation des bibliothèques est exactement la même que pour la première application.

 cd ...
 cd app2/
 symfony composer req amqp ampq-messenger monolog

Veillons à ce que le app2/.env contient une entrée DSN valide pour RabbitMQ :

(...)
 MESSENGER_TRANSPORT_DSN=amqp://user:password@rabbitmq:5672//messages
 (...)

Il ne reste plus qu'à configurer Symfony Messenger dans le fichier app2/config/packages/messenger.yaml file:

cadre :
messager :
# Décommentez ceci (et le transport failed ci-dessous) pour envoyer les messages échoués à ce transport en vue d'un traitement ultérieur.
# failure_transport : failed

    transports :
        # https://symfony.com/doc/current/messenger.html#transport-configuration
        async :
            dsn : '%env(MESSENGER_TRANSPORT_DSN)%'

    routing :
        # Routez vos messages vers les transports
        AppMessageStatusUpdate' : async

Comme vous pouvez le voir, cette fois-ci, la définition du transport pointe directement vers asynchrone et définit le routage sous la forme de l'envoi de notre Mise à jour de l'état vers le DSN configuré. Il ne reste plus qu'à créer la logique et la couche d'implémentation de la file d'attente AMQP. Pour ce faire, nous allons créer le jumeau StatusUpdateHandler et Mise à jour de l'état classes en app2.

image
 use PsrLogLoggerInterface ;
use SymfonyComponentMessengerAttributeAsMessageHandler ;

[AsMessageHandler]

classe StatusUpdateHandler
{
public function __construct(
private readonly LoggerInterface $logger,
) {}

public function __invoke(StatusUpdate $statusUpdate) : void
{
    $statusDescription = $statusUpdate->getStatus() ;

    $this->logger->warning('APP2 : {STATUS_UPDATE} - '.$statusDescription) ;

    ## logique métier, c'est-à-dire envoi d'une notification interne ou mise en file d'attente pour d'autres systèmes
}

}
image
 {
public function __construct(protected string $status){}

public function getStatus() : string
{
    return $this->status ;
}

}


Le code source est disponible directement : /thecodest-co/microservices-in-symfony/blob/main/app2/src/Message/StatusUpdate.php

Enfin, il ne reste plus qu'à créer un moyen d'envoyer un message au bus de messages. Nous allons créer un simple Commande Symfony pour cela :

image
use SymfonyComponentConsoleAttributeAsCommand ;
use SymfonyComponentConsoleCommandCommand ;
use SymfonyComponentConsoleInputInputInterface ;
use SymfonyComponentConsoleOutputOutputInterface ;
use SymfonyComponentMessengerMessageBusInterface ;

[AsCommand(

name : "app:send"

)]
class SendStatusCommand extends Command
{
public function construct(private readonly MessageBusInterface $messageBus, string $name = null)
{
parent::construct($name) ;
}

protected function execute(InputInterface $input, OutputInterface $output) : int
{
    $status = "Worker X assigned to Y" ;

    $this->messageBus->dispatch(
        message : new StatusUpdate($status)
    ) ;

    return Command::SUCCESS ;
}

}

Merci à Injection de dépendance nous pouvons utiliser une instance de MessageBusInterface dans notre commande et envoyer un Mise à jour de l'état par l'intermédiaire du dispatch() à notre file d'attente. En outre, nous utilisons également les attributs PHP ici.

Voilà, il ne reste plus qu'à lancer notre environnement Docker Compose et à voir comment se comportent nos applications.

Exécution de l'environnement et tests

Avec Docker Compose, les conteneurs contenant nos deux applications seront construits et exécutés en tant qu'instances séparées. lapinmq et notre mise en œuvre du bus de messages.

Depuis le répertoire racine du projet, exécutons les commandes suivantes :

cd ../ # assurez-vous d'être dans le répertoire principal
 docker-compose up --build -d

Cette commande peut prendre un certain temps, car elle construit deux conteneurs séparés avec PHP 8.1 + AMQP et tire l'image RabbitMQ. Soyez patient. Une fois les images construites, vous pouvez lancer notre commande à partir de app2 et envoyer des messages dans une file d'attente.

 docker exec -it app2 php bin/console app:send

Vous pouvez le faire autant de fois que vous le souhaitez. Tant qu'il n'y a pas de consommateur vos messages ne seront pas traités. Dès que vous lancez le app1 et consommer tous les messages qu'ils afficheront sur votre écran.

docker exec -it app1 php bin/console messenger:consume -vv external_messages
image

L'ensemble code source ainsi que le README peuvent être trouvés dans notre dépôt public The Codest Github

Résumé

Symfony, avec ses bibliothèques et ses outils, permet une approche rapide et efficace du développement d'applications modernes. applications web. Avec quelques commandes et quelques lignes de code, nous sommes en mesure de créer un système de communication moderne entre les applications. Symfony, comme PHPest idéal pour le développement d'applications web et grâce à son écosystème et à sa facilité de mise en œuvre, cet écosystème atteint certains des meilleurs indicateurs de délai de mise sur le marché.

Cependant, la rapidité n'est pas toujours synonyme de qualité - dans l'exemple ci-dessus, nous avons présenté le moyen de communication le plus simple et le plus rapide. Les plus curieux remarqueront certainement qu'il n'y a pas de déconnexion des événements de domaine en dehors de la couche d'application - dans la version actuelle, ils sont dupliqués, et il n'y a pas de support complet pour les événements de domaine. EnveloppeEntre autres, il n'y a pas de Timbres. Pour ceux-là et les autres, je vous invite à lire la partie II, où nous aborderons le sujet de l'unification de la structure de domaine des applications Symfony dans un environnement microservices, et discuterons de la deuxième méthode de communication microservices populaire - cette fois-ci synchrone, basée sur l'API REST.

bannière de coopération

Articles connexes

Développement de logiciels

PHP 8.2 : Quoi de neuf ?

La nouvelle version de PHP arrive à grands pas. Quelles sont les nouvelles implémentations que vous devez connaître ? Consultez cet article pour le savoir !

The Codest
Sebastian Luczak PHP Chef d'unité
Développement de logiciels

Développement PHP. Symfony Console Component - Trucs et astuces

Cet article a été créé dans le but de vous présenter les trucs et astuces les plus utiles et les plus récupérables concernant le développement de la console Symfony.

The Codest
Sebastian Luczak PHP Chef d'unité

Abonnez-vous à notre base de connaissances et restez au courant de l'expertise du secteur des technologies de l'information.

    A propos de nous

    The Codest - Entreprise internationale de développement de logiciels avec des centres technologiques en Pologne.

    Royaume-Uni - Siège

    • Bureau 303B, 182-184 High Street North E6 2JA
      Londres, Angleterre

    Pologne - Les pôles technologiques locaux

    • Parc de bureaux Fabryczna, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Varsovie, Pologne

      The Codest

    • Accueil
    • A propos de nous
    • Services
    • Études de cas
    • Savoir comment
    • Carrières
    • Dictionnaire

      Services

    • Conseil consultatif
    • Développement de logiciels
    • Développement backend
    • Développement frontal
    • Staff Augmentation
    • Développeurs backend
    • Ingénieurs en informatique dématérialisée
    • Ingénieurs des données
    • Autres
    • Ingénieurs AQ

      Ressources

    • Faits et mythes concernant la coopération avec un partenaire externe de développement de logiciels
    • Des États-Unis à l'Europe : Pourquoi les startups américaines décident-elles de se délocaliser en Europe ?
    • Comparaison des pôles de développement Tech Offshore : Tech Offshore Europe (Pologne), ASEAN (Philippines), Eurasie (Turquie)
    • Quels sont les principaux défis des CTO et des DSI ?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Conditions d'utilisation du site web

    Copyright © 2025 par The Codest. Tous droits réservés.

    fr_FRFrench
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish pl_PLPolish arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek fr_FRFrench