window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = finestra if (w.LeadBooster) { console.warn('LeadBooster esiste già') } 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: Comunicazione a microservizi parte I - The Codest
The Codest
  • Chi siamo
  • Servizi
    • Sviluppo di software
      • Sviluppo Frontend
      • Sviluppo backend
    • Staff Augmentation
      • Sviluppatori Frontend
      • Sviluppatori backend
      • Ingegneri dei dati
      • Ingegneri del cloud
      • Ingegneri QA
      • Altro
    • Consulenza
      • Audit e consulenza
  • Industrie
    • Fintech e banche
    • E-commerce
    • Adtech
    • Tecnologia della salute
    • Produzione
    • Logistica
    • Automotive
    • IOT
  • Valore per
    • CEO
    • CTO
    • Responsabile della consegna
  • Il nostro team
  • Case Studies
  • Sapere come
    • Blog
    • Incontri
    • Webinar
    • Risorse
Carriera Contattate
  • Chi siamo
  • Servizi
    • Sviluppo di software
      • Sviluppo Frontend
      • Sviluppo backend
    • Staff Augmentation
      • Sviluppatori Frontend
      • Sviluppatori backend
      • Ingegneri dei dati
      • Ingegneri del cloud
      • Ingegneri QA
      • Altro
    • Consulenza
      • Audit e consulenza
  • Valore per
    • CEO
    • CTO
    • Responsabile della consegna
  • Il nostro team
  • Case Studies
  • Sapere come
    • Blog
    • Incontri
    • Webinar
    • Risorse
Carriera Contattate
Freccia indietro TORNA INDIETRO
2022-06-28
Sviluppo di software

Symfony: Comunicazione a microservizi parte I

The Codest

Sebastian Luczak

PHP Capo unità

Leggete la prima parte della nostra serie PHP dedicata alla comunicazione dei microservizi nel framework Symfony e al modo più popolare: la comunicazione AMQP con RabbitMQ.

La moderna architettura delle applicazioni ha costretto gli sviluppatori a cambiare il modo di pensare alla comunicazione tra i diversi componenti dei sistemi IT. Un tempo la questione era più semplice: la maggior parte dei sistemi veniva creata come strutture monolitiche collegate tra loro da una rete di connessioni di logica aziendale. Il mantenimento di tali dipendenze in un PHP progetto è stata una grande sfida per Sviluppatori PHPe la crescente popolarità delle soluzioni SaaS e l'enorme aumento di popolarità delle soluzioni SaaS. nuvola servizi ha fatto sì che oggi si senta parlare sempre più spesso di microservizi e modularità delle applicazioni.

In che modo, creando microservizi indipendenti, possiamo far sì che si scambino informazioni tra loro?

Questo articolo è il primo di una serie di post su comunicazione dei microservizi in Symfony e copre il modo più diffuso: la comunicazione AMQP con RabbitMQ.

Obiettivo

Creare due applicazioni indipendenti e realizzare la comunicazione tra di esse utilizzando solo Message Bus.

Il concetto

Abbiamo due applicazioni immaginarie e indipendenti:
* app1che invia notifiche via e-mail e SMS ai dipendenti.
* app2che consente di gestire il lavoro dei dipendenti e di assegnare loro dei compiti.

Vogliamo creare un sistema moderno e semplice che consenta di assegnare il lavoro a un dipendente in un'unica soluzione. app2 invierà una notifica al cliente utilizzando app1. Nonostante le apparenze, è molto semplice!

Preparazione

Per lo scopo di questo articolo, utilizzeremo l'ultima versione di Symfony (la 6.1 al momento della scrittura) e l'ultima versione di PHP (8.1). In pochi e semplici passi creeremo un ambiente Docker locale funzionante con due microservizi. Tutto ciò che serve è:
* un computer funzionante,
* installato Docker + Ambiente Docker Compose
* e una configurazione locale Symfony CLI e un po' di tempo libero.

Ambiente di runtime

Utilizzeremo le capacità di Docker come strumento di virtualizzazione e containerizzazione delle applicazioni. Cominciamo con la creazione di un albero di directory, una struttura per due Applicazioni Symfonye descrivere l'infrastruttura dei nostri ambienti utilizzando l'opzione docker-compose.yml file.

 cd ~
 mkdir microservizi-in-symfony
 cd microservizi-in-symfony
 symfony nuova app1
 symfony nuova app2
 toccare docker-compose.yml

Abbiamo creato due cartelle per due applicazioni Symfony separate e abbiamo creato una cartella vuota docker-compose.yml per lanciare il nostro ambiente.

Aggiungiamo le seguenti sezioni al file docker-compose.yml file:

versione: '3.8'

servizi:
app1:
containername: app1
build: app1/.
restart: on-failure
envfile: app1/.env
ambiente:
APPNAME: app1
tty: true
stdinopen: true

app2:
containername: app2
build: app2/.
restart: on-failure
envfile: app2/.env
ambiente:
APPNAME: app2
tty: true
stdinopen: true

rabbitmq:
containername: rabbitmq
immagine: rabbitmq:management
porte:
- 15672:15672
- 5672:5672
ambiente:
- RABBITMQDEFAULTUSER=utente
- RABBITMQDEFAULT_PASS=password

Fonte codice disponibili direttamente: thecodest-co/microservizi-in-symfony/blob/main/docker-compose.yml

Ma aspettate, cosa è successo qui? Per chi non ha familiarità con Docker, il file di configurazione di cui sopra può sembrare enigmatico, tuttavia il suo scopo è molto semplice. Utilizzando Docker Compose stiamo costruendo tre "servizi":

  • app1: che è un contenitore per la prima applicazione Symfony
  • app2: che è il contenitore per la seconda applicazione Symfony
  • rabbitmq: l'immagine dell'applicazione RabbitMQ come livello di middleware per la comunicazione

Per un corretto funzionamento, abbiamo ancora bisogno di Profilo Docker che sono il sorgente per costruire le immagini. Quindi creiamoli:

 toccare app1/Dockerfile
 toccare app2/Dockerfile

Entrambi i file hanno esattamente la stessa struttura e si presentano come segue:

DA php:8.1

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPIA . /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 &&
installa-php-estensioni amqp

ESEGUIRE 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/*

ESEGUIRE docker-php-ext-install zip;

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

Il codice sorgente è disponibile direttamente: /thecodest-co/microservizi-in-symfony/blob/main/app1/Dockerfile

Il file di cui sopra viene usato da Docker Compose per costruire un contenitore da un'immagine PHP 8.1 con Composer e l'estensione AMQP installata. Inoltre, esegue l'inteprete PHP in modalità append per mantenere il contenitore in esecuzione in background.

La struttura delle directory e dei file dovrebbe ora apparire come segue:

 .
 ├── app1
 │ └── Dockerfile
 | # Struttura dell'applicazione Symfony
 ├── app2
 │ └─── Dockerfile
 | # Struttura dell'applicazione Symfony
 └── docker-compose.yml

Il primo microservizio Symfony

Iniziamo con il app1 e la prima applicazione.
Nel nostro esempio, si tratta di un'applicazione che ascolta e consuma i messaggi della coda inviati da app2 come descritto nei requisiti:

assegnare un lavoro a un lavoratore in app2 invierà una notifica al client

Iniziamo aggiungendo le librerie necessarie. AMQP è supportato in modo nativo per il sistema symfony/messenger estensione. Inoltre, installeremo monologo/monologo per tenere traccia dei registri di sistema e facilitare l'analisi del comportamento delle applicazioni.

 cd app1/
 symfony composer req amqp ampq-messenger monolog

Dopo l'installazione, è stato aggiunto un file supplementare sotto la voce config/packages/messenger.yaml. Si tratta di un file di configurazione per il componente Symfony Messenger e non abbiamo bisogno del suo configurazione completa.
Sostituirlo con il file YAML seguente:

quadro:
messenger:
# Deselezionare questo (e il trasporto failed sotto) per inviare i messaggi falliti a questo trasporto per una successiva gestione.
# trasporto_fallito: fallito

    trasporti:
        # https://symfony.com/doc/current/messenger.html#transport-configuration
        messaggi_esterni:
            dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
            opzioni:
                auto_setup: false
                scambio:
                    nome: messaggi
                    tipo: diretto
                    chiave di instradamento predefinita: from_external
                code:
                    messaggi:
                        binding_keys: [da_esterno]

Il codice sorgente è disponibile direttamente: thecodest-co/microservices-in-symfony/blob/main/app1/config/packages/messenger.yaml

Symfony Messenger è usato per la comunicazione sincrona e asincrona nelle applicazioni Symfony. Supporta una varietà di trasportio fonti di verità del livello di trasporto. Nel nostro esempio, utilizziamo l'estensione AMQP che supporta il sistema di code di eventi RabbitMQ.

La configurazione precedente definisce un nuovo trasporto chiamato messaggi_esterniche fa riferimento al file MESSENGER_TRANSPORT_DSN e definisce l'ascolto diretto sul server messaggi in Message Bus. A questo punto, modificare anche l'opzione app1/.env e aggiungere l'indirizzo di trasporto appropriato.

"`env

(...)
MESSENGERTRANSPORTDSN=amqp://user:password@rabbitmq:5672//messages
(...)
"
Dopo aver preparato il framework dell'applicazione e configurato le librerie, è il momento di implementare la logica di business. Sappiamo che la nostra applicazione deve rispondere all'assegnazione di un lavoro a un lavoratore. Sappiamo anche che l'assegnazione di un lavoro inapp2system cambia lo stato del lavoro. Creiamo quindi un modello che imiti il cambiamento di stato e salviamolo nel percorsoapp1/Message/StatusUpdate.php:
immagine
 {
public function __construct(protected string $status){}

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

}

Il codice sorgente è disponibile direttamente: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Message/StatusUpdate.php

Abbiamo ancora bisogno di una classe che implementi la logica di business quando il nostro microservizio riceve l'evento di cui sopra dalla coda. Creiamo quindi una classe Gestore dei messaggi nel app1/Handler/StatusUpdateHandler.php percorso:

immagine
 utilizzare 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);

    // il resto della logica aziendale, cioè l'invio di e-mail all'utente
    // $this->emailService->email()
}

}

Il codice sorgente è disponibile direttamente: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Handler/StatusUpdateHandler.php

PHP rende le cose molto più semplici e significa che in questo caso particolare non dobbiamo preoccuparci dell'autowiring o della dichiarazione del servizio. Il nostro microservizio per la gestione degli eventi del dominio è pronto, è ora di passare alla seconda applicazione.

Secondo microservizio Symfony

Daremo un'occhiata al app2 e la seconda cartella Applicazione Symfony. La nostra idea è di inviare un messaggio alla coda quando a un lavoratore viene assegnato un compito nel sistema. Quindi, facciamo una rapida configurazione di AMQP e facciamo partire la pubblicazione del nostro secondo microservizio Aggiornamento dello stato eventi al bus dei messaggi.

L'installazione delle librerie è esattamente la stessa della prima applicazione.

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

Assicuriamoci che il app2/.env contiene una voce DSN valida per RabbitMQ:

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

Rimane solo da configurare Symfony Messenger nella cartella app2/config/packages/messenger.yaml file:

quadro:
messenger:
# Deselezionare questo (e il trasporto failed sotto) per inviare i messaggi falliti a questo trasporto per una successiva gestione.
# trasporto_fallito: fallito

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

    instradamento:
        # Instradare i messaggi ai trasporti
        AppMessageStatusUpdate': async

Come si può vedere, questa volta la definizione di trasporto punta direttamente a asincrono e definisce l'instradamento sotto forma di invio del nostro Aggiornamento dello stato al DSN configurato. Questa è l'unica area di configurazione, tutto ciò che rimane è creare la logica e il livello di implementazione della coda AMQP. Per questo creeremo il gemello Gestore dell'aggiornamento dello stato e Aggiornamento dello stato classi in app2.

immagine
 utilizzare 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);

    ## logica aziendale, ad esempio invio di una notifica interna o messa in coda ad altri sistemi
}

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

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

}


Il codice sorgente è disponibile direttamente: /thecodest-co/microservices-in-symfony/blob/main/app2/src/Message/StatusUpdate.php

Infine, non resta che creare un modo per inviare un messaggio al Message Bus. Creeremo un semplice oggetto Comando Symfony per questo:

immagine
utilizzare SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
use SymfonyComponentMessengerMessageBusInterface;

[AsCommand(

nome: "app:send"

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

protected function execute(InputInterface $input, OutputInterface $output): int
{
    $status = "Lavoratore X assegnato a Y";

    $this->messageBus->dispatch(
        messaggio: nuovo StatusUpdate($status)
    );

    restituire Command::SUCCESS;
}

}

Grazie a Iniezione di dipendenza possiamo utilizzare un'istanza di Interfaccia MessageBus nel nostro comando e inviare un messaggio Aggiornamento dello stato tramite il messaggio dispatch() alla nostra coda. Inoltre, qui utilizziamo anche gli attributi PHP.

Tutto qui: non resta che eseguire il nostro ambiente Docker Compose e vedere come si comportano le nostre applicazioni.

Esecuzione dell'ambiente e test

Con Docker Compose i container con le nostre due applicazioni saranno costruiti ed eseguiti come istanze separate, l'unico livello di middleware sarà il conigliomq e la nostra implementazione del Bus dei messaggi.

Dalla directory principale del progetto, eseguiamo i seguenti comandi:

cd ../ # assicurarsi di essere nella directory principale
 docker-compose up --build -d

Questo comando può richiedere un po' di tempo, poiché costruisce due contenitori separati con PHP 8.1 + AMQP e tira l'immagine di RabbitMQ. Siate pazienti. Dopo che le immagini sono state costruite, si può lanciare il nostro comando da app2 e inviare alcuni messaggi in una coda.

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

Potete farlo quante volte volete. Finché non c'è consumatore i messaggi non verranno elaborati. Non appena si accende il programma app1 e consumare tutti i messaggi che verranno visualizzati sullo schermo.

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

L'opera completa codice sorgente insieme al README è disponibile nel nostro repository pubblico The Codest Github

Sintesi

Symfony, con le sue librerie e i suoi strumenti, permette un approccio veloce ed efficiente allo sviluppo di moderne applicazioni web. Con pochi comandi e poche righe di codice siamo in grado di creare un moderno sistema di comunicazione tra applicazioni. Symfony, come PHPè ideale per sviluppare applicazioni web e grazie al suo ecosistema e alla facilità di implementazione, questo ecosistema raggiunge alcuni dei migliori indicatori di time-to-market.

Tuttavia, veloce non sempre significa buono: nell'esempio precedente abbiamo presentato il modo più semplice e veloce di comunicazione. I più curiosi noteranno sicuramente che manca la disconnessione degli eventi di dominio al di fuori del livello applicativo: nella versione attuale sono duplicati e non c'è un supporto completo per Busta, tra l'altro non c'è Francobolli. Per questi e altri argomenti, vi invito a leggere la Parte II, dove tratteremo l'argomento dell'unificazione della struttura del dominio delle applicazioni Symfony in un ambiente di microservizi e discuteremo il secondo metodo di comunicazione dei microservizi, questa volta sincrono, basato sulle API REST.

banner di cooperazione

Articoli correlati

Sviluppo di software

PHP 8.2: cosa c'è di nuovo?

La nuova versione di PHP è alle porte. Quali sono le nuove implementazioni da conoscere? Consultate questo articolo per scoprirlo!

The Codest
Sebastian Luczak PHP Capo unità
Sviluppo di software

Sviluppo PHP. Componente console di Symfony - Suggerimenti e trucchi

Questo articolo è stato creato con l'obiettivo di mostrare i consigli e i trucchi più utili e interessanti sullo sviluppo di Symfony Console.

The Codest
Sebastian Luczak PHP Capo unità

Iscrivetevi alla nostra knowledge base e rimanete aggiornati sulle competenze del settore IT.

    Chi siamo

    The Codest - Società internazionale di sviluppo software con centri tecnologici in Polonia.

    Regno Unito - Sede centrale

    • Ufficio 303B, 182-184 High Street North E6 2JA
      Londra, Inghilterra

    Polonia - Poli tecnologici locali

    • Parco uffici Fabryczna, Aleja
      Pokoju 18, 31-564 Cracovia
    • Ambasciata del cervello, Konstruktorska
      11, 02-673 Varsavia, Polonia

      The Codest

    • Casa
    • Chi siamo
    • Servizi
    • Case Studies
    • Sapere come
    • Carriera
    • Dizionario

      Servizi

    • Consulenza
    • Sviluppo di software
    • Sviluppo backend
    • Sviluppo Frontend
    • Staff Augmentation
    • Sviluppatori backend
    • Ingegneri del cloud
    • Ingegneri dei dati
    • Altro
    • Ingegneri QA

      Risorse

    • Fatti e miti sulla collaborazione con un partner esterno per lo sviluppo di software
    • Dagli Stati Uniti all'Europa: Perché le startup americane decidono di trasferirsi in Europa
    • Confronto tra gli hub di sviluppo Tech Offshore: Tech Offshore Europa (Polonia), ASEAN (Filippine), Eurasia (Turchia)
    • Quali sono le principali sfide di CTO e CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Condizioni di utilizzo del sito web

    Copyright © 2025 di The Codest. Tutti i diritti riservati.

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