window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(funktion () { var w = vindue if (w.LeadBooster) { console.warn('LeadBooster findes allerede') } 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-kommunikation del I - The Codest
Codest
  • Om os
  • Serviceydelser
    • Udvikling af software
      • Frontend-udvikling
      • Backend-udvikling
    • Staff Augmentation
      • Frontend-udviklere
      • Backend-udviklere
      • Dataingeniører
      • Cloud-ingeniører
      • QA-ingeniører
      • Andet
    • Det rådgivende
      • Revision og rådgivning
  • Industrier
    • Fintech og bankvirksomhed
    • E-commerce
    • Adtech
    • Sundhedsteknologi
    • Produktion
    • Logistik
    • Biler
    • IOT
  • Værdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leder af levering
  • Vores team
  • Casestudier
  • Ved hvordan
    • Blog
    • Møder
    • Webinarer
    • Ressourcer
Karriere Tag kontakt til os
  • Om os
  • Serviceydelser
    • Udvikling af software
      • Frontend-udvikling
      • Backend-udvikling
    • Staff Augmentation
      • Frontend-udviklere
      • Backend-udviklere
      • Dataingeniører
      • Cloud-ingeniører
      • QA-ingeniører
      • Andet
    • Det rådgivende
      • Revision og rådgivning
  • Værdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leder af levering
  • Vores team
  • Casestudier
  • Ved hvordan
    • Blog
    • Møder
    • Webinarer
    • Ressourcer
Karriere Tag kontakt til os
Pil tilbage GÅ TILBAGE
2022-06-28
Udvikling af software

Symfony: Microservices-kommunikation del I

Codest

Sebastian Luczak

PHP Enhedsleder

Læs første del af vores PHP-serie om kommunikation mellem mikrotjenester i Symfony-framework og den mest populære måde - AMQP-kommunikation ved hjælp af RabbitMQ.

Moderne applikationsarkitektur har tvunget udviklere til at ændre deres måde at tænke på, når det gælder kommunikationen mellem forskellige komponenter i IT-systemer. Engang var sagen enklere - de fleste systemer blev skabt som monolitiske strukturer, der var forbundet med hinanden via et netværk af forretningslogiske forbindelser. Vedligeholdelse af sådanne afhængigheder i en PHP projekt var en stor udfordring for PHP-udviklereog den voksende popularitet af SaaS-løsninger og den enorme stigning i populariteten af sky Tjenesterne er skyld i, at vi i dag hører mere og mere om mikrotjenester og applikationsmodularitet.

Hvordan kan vi ved at skabe uafhængige mikrotjenester få dem til at udveksle information med hinanden?

Denne artikel er den første i en række indlæg om Kommunikation mellem mikrotjenester i Symfony og den dækker den mest populære måde - AMQP-kommunikation ved hjælp af RabbitMQ.

Mål

At skabe to uafhængige applikationer og opnå kommunikation mellem dem ved kun at bruge Message Bus.

Konceptet

Vi har to imaginære, uafhængige applikationer:
* app1: som sender e-mail- og sms-beskeder til medarbejderne
* app2: som giver dig mulighed for at styre medarbejdernes arbejde og tildele dem opgaver.

Vi ønsker at skabe et moderne og enkelt system, hvor tildelingen af arbejde til en medarbejder i app2 vil sende en meddelelse til kunden ved hjælp af app1. På trods af udseendet er det meget enkelt!

Forberedelse

I denne artikel bruger vi den nyeste Symfony (version 6.1 i skrivende stund) og den nyeste version af PHP (8.1). Med et par meget enkle trin opretter vi et fungerende lokalt Docker-miljø med to mikrotjenester. Alt, hvad du har brug for, er:
* en fungerende computer,
* installeret Docker + Docker Compose-miljø
* og en lokalt konfigureret Symfony CLI og lidt fritid.

Runtime-miljø

Vi vil bruge Dockers evner som et værktøj til virtualisering og containerisering af applikationer. Lad os starte med at oprette et katalogtræ, en ramme for to Symfony-applikationerog beskrive infrastrukturen i vores miljøer ved hjælp af docker-compose.yml fil.

 cd ~
 mkdir microservices-in-symfony
 cd microservices-i-symfony
 symfony ny app1
 symfony ny app2
 tryk på docker-compose.yml

Vi har oprettet to mapper til to separate Symfony-applikationer og oprettet en tom docker-compose.yml fil for at starte vores miljø.

Lad os tilføje følgende afsnit til docker-compose.yml file:

version: '3.8'

tjenester:
app1:
containername: app1
build: app1/.
restart: on-failure
envfil: app1/.env
environment:
APPNAME: app1
tty: true
stdinopen: true

app2:
containername: app2
build: app2/.
restart: on-failure
envfil: app2/.env
environment:
APPNAME: app2
tty: true
stdinopen: true

rabbitmq:
containername: rabbitmq
image: rabbitmq:management
porte:
- 15672:15672
- 5672:5672
miljø:
- RABBITMQDEFAULTUSER=bruger
- RABBITMQDEFAULT_PASS=password

Kilde Kode tilgængelig direkte: thecodest-co/microservices-in-symfony/blob/main/docker-compose.yml

Men vent, hvad skete der her? For dem, der ikke er fortrolige med Docker, kan ovenstående konfigurationsfil virke gådefuld, men dens formål er meget enkelt. Ved hjælp af Docker Compose bygger vi tre "tjenester":

  • app1: som er en container til den første Symfony-applikation
  • app2: som er containeren til den anden Symfony-applikation
  • rabbitmq: RabbitMQ-applikationsbilledet som et kommunikationsmellemlag

For at fungere ordentligt har vi stadig brug for Dockerfil filer, som er kilden til at bygge billederne. Så lad os oprette dem:

 touch app1/Dockerfile
 tryk på app2/Dockerfile

Begge filer har nøjagtig samme struktur og ser ud som følger:

FRA 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-udvidelser amqp

KØR 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/*

Kør docker-php-ext-install zip;

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

Kildekoden er tilgængelig direkte: /thecodest-co/microservices-in-symfony/blob/main/app1/Dockerfile

Ovenstående fil bruges af Docker Compose til at bygge en container fra et PHP 8.1-image med Composer og AMQP-udvidelsen installeret. Derudover kører den PHP intepreter i append-tilstand for at holde containeren kørende i baggrunden.

Dit mappe- og filtræ bør nu se ud som følger:

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

Den første Symfony-mikrotjeneste

Lad os starte med app1 og den første applikation.
I vores eksempel er det et program, der lytter og bruger beskeder fra køen sendt af app2 som beskrevet i kravene:

tildele et job til en medarbejder i app2 vil sende en meddelelse til klienten

Lad os starte med at tilføje de nødvendige biblioteker. AMQP understøttes naturligt af symfony/messenger udvidelse. Vi vil desuden installere monolog/monolog til at holde styr på systemlogs for lettere at kunne analysere programadfærd.

 cd app1/
 symfony composer req amqp ampq-messenger monolog

Efter installationen blev der tilføjet en ekstra fil under config/packages/messenger.yaml. Det er en konfigurationsfil til Symfony Messenger-komponenten, og vi har ikke brug for den. Fuld konfiguration.
Erstat den med YAML-filen nedenfor:

rammer:
messenger:
# Fjern kommentarerne til denne (og den mislykkede transport nedenfor) for at sende mislykkede beskeder til denne transport til senere håndtering.
# fejl_transport: fejlede

    transporter:
        # https://symfony.com/doc/current/messenger.html#transport-configuration
        eksterne_meddelelser:
            dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
            options:
                auto_setup: false
                udveksling:
                    navn: beskeder
                    type: direkte
                    default_publish_routing_key: from_external
                køer:
                    messages:
                        binding_keys: [from_external]

Kildekoden er tilgængelig direkte: thecodest-co/microservices-in-symfony/blob/main/app1/config/packages/messenger.yaml

Symfony Messenger bruges til synkron og asynkron kommunikation i Symfony-applikationer. Den understøtter en række transportereller kilder til sandhed i transportlaget. I vores eksempel bruger vi AMQP-udvidelsen, der understøtter RabbitMQ-eventkøsystemet.

Ovenstående konfiguration definerer en ny transport med navnet eksterne_beskedersom refererer til MESSENGER_TRANSPORT_DSN miljøvariabel og definerer direkte lytning på Beskeder kanal i Message Bus. På dette tidspunkt skal du også redigere app1/.env og tilføj den relevante transportadresse.

"`env

(...)
MESSENGERTRANSPORTDSN=amqp://user:password@rabbitmq:5672//messages
(...)
"
Efter at have forberedt applikationsrammen og konfigureret bibliotekerne er det tid til at implementere forretningslogikken. Vi ved, at vores applikation skal reagere på tildelingen af et job til en worker. Vi ved også, at tildeling af et job i theapp2system ændrer jobbets status. Så lad os skabe en model, der efterligner statusændringen, og gemme den i stienapp1/Message/StatusUpdate.php`:
billede
 {
public function __construct(protected string $status){}

offentlig funktion getStatus(): string
{
    return $this->status;
}

}

Kildekoden er tilgængelig direkte: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Message/StatusUpdate.php

Vi har stadig brug for en klasse, der implementerer forretningslogikken, når vores mikrotjeneste modtager ovenstående hændelse fra køen. Så lad os oprette en Beskedhåndtering i app1/Handler/StatusUpdateHandler.php vej:

billede
 brug PsrLogLoggerInterface;
brug SymfonyComponentMessengerAttributeAsMessageHandler;

[AsMessageHandler]

klasse StatusUpdateHandler
{
offentlig funktion __construct(
protected LoggerInterface $logger,
) {}

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

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

    // resten af forretningslogikken, dvs. at sende e-mail til brugeren
    // $this->emailService->email()
}

}

Kildekoden er tilgængelig direkte: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Handler/StatusUpdateHandler.php

PHP attributter gør tingene meget nemmere og betyder, at vi i dette tilfælde ikke behøver at bekymre os om autowiring eller serviceerklæring. Vores mikroservice til håndtering af domænebegivenheder er klar, og det er tid til at gå i gang med den anden applikation.

Anden Symfony-mikroservice

Vi tager et kig på app2 mappe og den anden Symfony-applikation. Vores idé er at sende en besked til køen, når en medarbejder får tildelt en opgave i systemet. Så lad os lave en hurtig konfiguration af AMQP og få vores anden mikrotjeneste til at begynde at udgive Statusopdatering begivenheder til beskedbussen.

Installationen af bibliotekerne er nøjagtig den samme som for den første applikation.

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

Lad os sørge for, at app2/.env filen indeholder en gyldig DSN-post for RabbitMQ:

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

Det eneste, der er tilbage, er at konfigurere Symfony Messenger i app2/config/packages/messenger.yaml file:

rammer:
messenger:
# Fjern kommentarerne til denne (og den mislykkede transport nedenfor) for at sende mislykkede beskeder til denne transport til senere håndtering.
# fejl_transport: fejlede

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

    routing:
        # Send dine beskeder videre til transporterne
        'AppMessageStatusUpdate': async

Som du kan se, peger transportdefinitionen denne gang direkte på asynkron og definerer routing i form af at sende vores Statusopdatering besked til det konfigurerede DSN. Dette er det eneste konfigurationsområde, og det eneste, der er tilbage, er at skabe AMQP-køens logik- og implementeringslag. Til dette vil vi oprette tvillingen StatusUpdateHandler og Statusopdatering klasser i app2.

billede
 brug PsrLogLoggerInterface;
brug SymfonyComponentMessengerAttributeAsMessageHandler;

[AsMessageHandler]

klasse StatusUpdateHandler
{
offentlig funktion __construct(
private readonly LoggerInterface $logger,
) {}

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

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

    ## forretningslogik, dvs. sende intern notifikation eller sætte andre systemer i kø
}

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

offentlig funktion getStatus(): string
{
    return $this->status;
}

}


Kildekoden er tilgængelig direkte: /thecodest-co/microservices-in-symfony/blob/main/app2/src/Message/StatusUpdate.php

Til sidst mangler vi bare at skabe en måde at sende en besked til beskedbussen på. Vi vil oprette en simpel Symfony-kommando for dette:

billede
brug SymfonyComponentConsoleAttributeAsCommand;
brug SymfonyComponentConsoleCommandCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
brug SymfonyComponentMessengerMessageBusInterface;

[AsCommand(

navn: "app:send"

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

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

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

    return Command::SUCCESS;
}

}

Tak til Afhængighedsindsprøjtning kan vi bruge en forekomst af BeskedBusInterface i vores kommando og sende en Statusopdatering meddelelse via afsendelse() metode til vores kø. Derudover bruger vi også PHP-attributter her.

Det var det - nu er der kun tilbage at køre vores Docker Compose-miljø og se, hvordan vores applikationer opfører sig.

Kørsel af miljøet og testning

Med Docker Compose vil containerne med vores to applikationer blive bygget og kørt som separate instanser, og det eneste middleware-lag vil være kaninmq container og vores Message Bus-implementering.

Lad os køre følgende kommandoer fra projektets rodmappe:

cd ../ # sørg for, at du er i hovedmappen
 docker-compose up --build -d

Denne kommando kan tage lidt tid, da den bygger to separate containere med PHP 8.1 + AMQP og trækker RabbitMQ-image. Vær tålmodig. Når billederne er bygget, kan du starte vores kommando fra app2 og sende nogle beskeder til en kø.

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

Du kan gøre det så mange gange, du kan. Så længe der ikke er nogen forbruger vil dine beskeder ikke blive behandlet. Så snart du starter app1 og forbruge alle de beskeder, de viser på din skærm.

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

Den komplette Kildekode sammen med README kan findes i vores offentlige repository The Codest Github

Sammenfatning

Symfony med sine biblioteker og værktøjer giver mulighed for en hurtig og effektiv tilgang til udvikling af moderne webapplikationer. Med nogle få kommandoer og nogle få kodelinjer kan vi skabe et moderne kommunikationssystem mellem applikationer. Symfony, ligesom PHPer ideel til udvikling af webapplikationer og takket være sit økosystem og lette implementering opnår dette økosystem nogle af de bedste time-to-market-indikatorer.

Men hurtigt betyder ikke altid godt - i eksemplet ovenfor præsenterede vi den enkleste og hurtigste måde at kommunikere på. De mere nysgerrige vil helt sikkert bemærke, at der mangler en frakobling af domænebegivenheder uden for applikationslaget - i den nuværende version er de duplikeret, og der er ikke fuld understøttelse af KonvolutDer er blandt andet ingen Frimærker. For dem og andre inviterer jeg dig til at læse del II, hvor vi dækker emnet om at forene domænestrukturen i Symfony-applikationer i et mikrotjenestemiljø og diskuterer den anden populære mikrotjenestekommunikationsmetode - denne gang synkron, baseret på REST API.

Samarbejdsbanner

Relaterede artikler

Udvikling af software

PHP 8.2: Hvad er nyt?

Den nye version af PHP er lige om hjørnet. Hvad er de nye implementeringer, du bør kende til? Tjek denne artikel for at finde ud af det!

Codest
Sebastian Luczak PHP Enhedsleder
Udvikling af software

PHP udvikling. Symfony-konsolkomponent - tips og tricks

Denne artikel er lavet med det formål at vise dig de mest nyttige og nyttige tips og tricks om Symfony Console Development.

Codest
Sebastian Luczak PHP Enhedsleder

Tilmeld dig vores vidensbase, og hold dig opdateret om ekspertisen fra it-sektoren.

    Om os

    The Codest - International softwareudviklingsvirksomhed med tech-hubs i Polen.

    Storbritannien - Hovedkvarter

    • Kontor 303B, 182-184 High Street North E6 2JA
      London, England

    Polen - Lokale teknologiske knudepunkter

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Hjerneambassaden, Konstruktorska
      11, 02-673 Warszawa, Polen

      Codest

    • Hjem
    • Om os
    • Serviceydelser
    • Casestudier
    • Ved hvordan
    • Karriere
    • Ordbog

      Serviceydelser

    • Det rådgivende
    • Udvikling af software
    • Backend-udvikling
    • Frontend-udvikling
    • Staff Augmentation
    • Backend-udviklere
    • Cloud-ingeniører
    • Dataingeniører
    • Andet
    • QA-ingeniører

      Ressourcer

    • Fakta og myter om at samarbejde med en ekstern softwareudviklingspartner
    • Fra USA til Europa: Hvorfor beslutter amerikanske startups sig for at flytte til Europa?
    • Sammenligning af Tech Offshore-udviklingsknudepunkter: Tech Offshore Europa (Polen), ASEAN (Filippinerne), Eurasien (Tyrkiet)
    • Hvad er de største udfordringer for CTO'er og CIO'er?
    • Codest
    • Codest
    • Codest
    • Privacy policy
    • Vilkår for brug af hjemmesiden

    Copyright © 2025 af The Codest. Alle rettigheder forbeholdes.

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