window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versjon: 2, } ;(function () { var w = vindu if (w.LeadBooster) { console.warn('LeadBooster finnes 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: Mikrotjenestekommunikasjon del I - The Codest
The Codest
  • Om oss
  • Tjenester
    • Programvareutvikling
      • Frontend-utvikling
      • Backend-utvikling
    • Staff Augmentation
      • Frontend-utviklere
      • Backend-utviklere
      • Dataingeniører
      • Ingeniører i skyen
      • QA-ingeniører
      • Annet
    • Det rådgivende
      • Revisjon og rådgivning
  • Industrier
    • Fintech og bankvirksomhet
    • E-commerce
    • Adtech
    • Helseteknologi
    • Produksjon
    • Logistikk
    • Bilindustrien
    • IOT
  • Verdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leveransesjef
  • Vårt team
  • Casestudier
  • Vet hvordan
    • Blogg
    • Møter
    • Webinarer
    • Ressurser
Karriere Ta kontakt med oss
  • Om oss
  • Tjenester
    • Programvareutvikling
      • Frontend-utvikling
      • Backend-utvikling
    • Staff Augmentation
      • Frontend-utviklere
      • Backend-utviklere
      • Dataingeniører
      • Ingeniører i skyen
      • QA-ingeniører
      • Annet
    • Det rådgivende
      • Revisjon og rådgivning
  • Verdi for
    • ADMINISTRERENDE DIREKTØR
    • CTO
    • Leveransesjef
  • Vårt team
  • Casestudier
  • Vet hvordan
    • Blogg
    • Møter
    • Webinarer
    • Ressurser
Karriere Ta kontakt med oss
Pil tilbake GÅ TILBAKE
2022-06-28
Programvareutvikling

Symfony: Mikrotjenestekommunikasjon del I

The Codest

Sebastian Luczak

PHP Enhetsleder

Les den første delen av vår PHP-serie om mikrotjenestekommunikasjon i Symfony-rammeverket og den mest populære måten - AMQP-kommunikasjon ved hjelp av RabbitMQ.

Moderne applikasjonsarkitektur har tvunget utviklere til å endre måten å tenke på når det gjelder kommunikasjonen mellom ulike komponenter i IT-systemer. En gang var saken enklere - de fleste systemer ble laget som monolittiske strukturer som var forbundet med hverandre gjennom et nettverk av forretningslogiske forbindelser. Å opprettholde slike avhengigheter i en PHP prosjekt var en stor utfordring for PHP-utviklereog den økende populariteten til SaaS-løsninger og den enorme økningen i populariteten til sky tjenester førte til at vi i dag hører mer og mer om mikrotjenester og applikasjonsmodularitet.

Hvordan kan vi få dem til å utveksle informasjon med hverandre ved å lage uavhengige mikrotjenester?

Denne artikkelen er den første i en serie innlegg om mikrotjenestekommunikasjon i Symfony rammeverket, og den dekker den mest populære måten - AMQP-kommunikasjon ved hjelp av RabbitMQ.

Mål

Å opprette to uavhengige applikasjoner og oppnå kommunikasjon mellom dem kun ved hjelp av Message Bus.

Konseptet

Vi har to, imaginære, uavhengige applikasjoner:
* app1: som sender e-post- og SMS-varsler til de ansatte
* app2: som lar deg administrere de ansattes arbeid og tildele dem oppgaver.

Vi ønsker å skape et moderne og enkelt system der tildelingen av arbeid til en medarbeider i app2 vil sende et varsel til kunden ved hjelp av app1. Til tross for at det ser slik ut, er dette veldig enkelt!

Forberedelse

I denne artikkelen bruker vi den nyeste versjonen av Symfony (versjon 6.1 i skrivende stund) og den nyeste versjonen av PHP (8.1). Med noen få, enkle trinn kan vi opprette et fungerende lokalt Docker-miljø med to mikrotjenester. Alt du trenger er:
* en fungerende datamaskin,
* installert Docker + Docker Compose-miljø
* og en lokalt konfigurert Symfony CLI og litt fritid.

Kjøretidsmiljø

Vi vil bruke Dockers egenskaper som et verktøy for applikasjonsvirtualisering og containerisering. La oss starte med å lage et katalogtre, et rammeverk for to Symfony-applikasjonerog beskrive infrastrukturen i miljøene våre ved hjelp av docker-compose.yml fil.

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

Vi har opprettet to kataloger for to separate Symfony-applikasjoner og opprettet en tom docker-compose.yml filen for å starte miljøet vårt.

La oss legge til følgende seksjoner i docker-compose.yml file:

versjon: '3.8'

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

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

rabbitmq:
containername: rabbitmq
image: rabbitmq:management
ports:
- 15672:15672
- 5672:5672
environment:
- RABBITMQDEFAULTUSER=bruker
- RABBITMQDEFAULT_PASS=passord

Kilde kode tilgjengelig direkte: thecodest-co/microservices-in-symfony/blob/main/docker-compose.yml

Men vent, hva skjedde her? For de som ikke er kjent med Docker, kan konfigurasjonsfilen ovenfor virke gåtefull, men formålet med den er veldig enkelt. Ved hjelp av Docker Compose bygger vi tre "tjenester":

  • app1: som er en container for den første Symfony-applikasjonen
  • app2: som er containeren for den andre Symfony-applikasjonen
  • rabbitmq: RabbitMQ-applikasjonsbildet som et kommunikasjonsmellomvarelag

For riktig drift trenger vi fortsatt Dockerfil filer som er kilden til å bygge bildene. Så la oss lage dem:

 touch app1/Dockerfile
 touch app2/Dockerfile

Begge filene har nøyaktig samme struktur og ser ut 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-utvidelser amqp

KJØ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/*

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

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

Kildekoden er tilgjengelig direkte: /thecodest-co/mikrotjenester-i-symfony/blob/main/app1/Dockerfile

Filen ovenfor brukes av Docker Compose til å bygge en container fra et PHP 8.1-bilde med Composer og AMQP-utvidelsen installert. I tillegg kjører den PHP intepreter i append-modus for å holde beholderen i gang i bakgrunnen.

Katalog- og filtreet ditt skal nå se ut som følger:

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

Den første Symfony-mikrotjenesten

La oss begynne med app1 katalogen og den første applikasjonen.
I vårt eksempel er det en applikasjon som lytter til og bruker meldinger fra køen som sendes av app2 som beskrevet i kravene:

tildele en jobb til en arbeider i app2 vil sende et varsel til klienten

La oss begynne med å legge til de nødvendige bibliotekene. AMQP støttes naturlig for symfony/messenger forlengelse. Vi vil i tillegg installere monolog/monolog for å holde oversikt over systemlogger slik at det blir enklere å analysere programatferd.

 cd app1/
 symfony composer req amqp ampq-messenger monolog

Etter installasjonen ble det lagt til en ekstra fil under config/packages/messenger.yaml. Det er en konfigurasjonsfil for Symfony Messenger-komponenten, og vi trenger ikke dens full konfigurasjon.
Erstatt den med YAML-filen nedenfor:

rammeverk:
messenger:
# Fjern kommentarene for denne (og den mislykkede transporten nedenfor) for å sende mislykkede meldinger til denne transporten for senere håndtering.
# failure_transport: mislyktes

    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
                køer
                    messages:
                        binding_keys: [from_external]

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

Symfony Messenger brukes til synkron og asynkron kommunikasjon i Symfony-applikasjoner. Den støtter en rekke forskjellige transportereller sannhetskilder i transportlaget. I vårt eksempel bruker vi AMQP-utvidelsen som støtter hendelseskø-systemet RabbitMQ.

Konfigurasjonen ovenfor definerer en ny transport med navnet eksterne_meldinger, som refererer til MESSENGER_TRANSPORT_DSN miljøvariabel og definerer direkte lytting på meldinger kanalen i Message Bus. På dette tidspunktet redigerer du også app1/.env filen og legge til riktig transportadresse.

"`env

(...)
MESSENGERTRANSPORTDSN=amqp://user:password@rabbitmq:5672//messages
(...)
"
Etter å ha klargjort applikasjonsrammeverket og konfigurert bibliotekene, er det på tide å implementere forretningslogikken. Vi vet at applikasjonen vår må svare på tildelingen av en jobb til en arbeider. Vi vet også at tildelingen av en jobb iapp2systemet endrer statusen til jobben. Så la oss lage en modell som etterligner statusendringen, og lagre den i stienapp1/Message/StatusUpdate.php`:
bilde
 {
public function __construct(protected string $status){}

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

}

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

Vi trenger fortsatt en klasse som implementerer forretningslogikken når mikrotjenesten vår mottar ovennevnte hendelse fra køen. Så la oss opprette en Meldingsbehandler i app1/Handler/StatusUpdateHandler.php sti:

bilde
 use PsrLogLoggerInterface;
use SymfonyComponentMessengerAttributeAsMessageHandler;

[AsMessageHandler]

class StatusUpdateHandler
{
offentlig funksjon __construct(
protected LoggerInterface $logger,
) {}

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

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

    // resten av forretningslogikken, dvs. sende e-post til brukeren
    // $this->emailService->email()
}

}

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

PHP attributtene gjør ting mye enklere og betyr at vi i dette tilfellet ikke trenger å bekymre oss for autokobling eller tjenesteerklæring. Mikrotjenesten vår for håndtering av domenehendelser er klar, og det er på tide å gå i gang med den andre applikasjonen.

Den andre Symfony-mikrotjenesten

Vi vil ta en titt på app2 katalogen og den andre Symfony-applikasjon. Tanken vår er å sende en melding til køen når en arbeider får tildelt en oppgave i systemet. Så la oss gjøre en rask konfigurasjon av AMQP og få vår andre mikrotjeneste til å begynne å publisere StatusOppdatering hendelser til meldingsbussen.

Installasjonen av bibliotekene foregår på nøyaktig samme måte som for den første applikasjonen.

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

La oss sørge for at app2/.env filen inneholder en gyldig DSN-oppføring for RabbitMQ:

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

Alt som gjenstår er å konfigurere Symfony Messenger i app2/config/packages/messenger.yaml file:

rammeverk:
messenger:
# Fjern kommentarene for denne (og den mislykkede transporten nedenfor) for å sende mislykkede meldinger til denne transporten for senere håndtering.
# failure_transport: mislyktes

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

    routing:
        # Rute meldingene dine til transport
        'AppMessageStatusUpdate': async

Som du kan se, peker transportdefinisjonen denne gangen direkte til asynkron og definerer ruting i form av å sende vår StatusOppdatering meldingen til det konfigurerte DSN-et. Dette er det eneste konfigurasjonsområdet, alt som gjenstår er å lage logikken og implementasjonslaget for AMQP-køen. For dette vil vi opprette tvillingen StatusUpdateHandler og StatusOppdatering klasser i app2.

bilde
 use PsrLogLoggerInterface;
use SymfonyComponentMessengerAttributeAsMessageHandler;

[AsMessageHandler]

class StatusUpdateHandler
{
offentlig funksjon __construct(
private readonly LoggerInterface $logger,
) {}

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

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

    ## forretningslogikk, f.eks. sende intern varsling eller sette andre systemer i kø
}

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

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

}


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

Til slutt gjenstår det bare å lage en måte å sende en melding til meldingsbussen på. Vi vil lage en enkel Symfony-kommando for dette:

bilde
bruk SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleConsoleCommandCommand;
use SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface; use SymfonyComponentMessenger
use SymfonyComponentMessengerMessageBusInterface;

[AsCommand(

navn: "app:send"

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

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

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

    return Command::SUCCESS;
}

}

Takk til Avhengighetsinjeksjon kan vi bruke en forekomst av MessageBusInterface i vår kommando og sende en StatusOppdatering melding via utsendelse() metoden til køen vår. I tillegg bruker vi også PHP-attributter her.

Det er alt som gjenstår, nemlig å kjøre Docker Compose-miljøet og se hvordan applikasjonene våre oppfører seg.

Kjører miljøet og tester

Med Docker Compose vil containerne med de to applikasjonene våre bli bygget og kjørt som separate instanser, og det eneste mellomvarelaget vil være rabbitmq container og vår Message Bus-implementering.

Fra rotkatalogen til prosjektet kjører vi følgende kommandoer:

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

Denne kommandoen kan ta litt tid, ettersom den bygger to separate containere med PHP 8.1 + AMQP og henter RabbitMQ-image. Vær tålmodig. Etter at bildene er bygget, kan du avfyre kommandoen vår fra app2 og sende noen meldinger i en kø.

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

Du kan gjøre det så mange ganger du kan. Så lenge det ikke er noen forbruker vil ikke meldingene dine bli behandlet. Så snart du starter opp app1 og konsumere alle meldingene de viser på skjermen.

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

Den komplette kildekode sammen med README finnes i vårt offentlige arkiv The Codest Github

Sammendrag

Symfony med sine biblioteker og verktøy gir en rask og effektiv tilnærming til utvikling av moderne webapplikasjoner. Med noen få kommandoer og noen få kodelinjer kan vi lage et moderne kommunikasjonssystem mellom applikasjoner. Symfony, i likhet med PHP, er ideell for utvikling av webapplikasjoner og takket være økosystemet og den enkle implementeringen oppnår dette økosystemet noen av de beste indikatorene for time-to-market.

Rask betyr imidlertid ikke alltid bra - i eksemplet ovenfor presenterte vi den enkleste og raskeste måten å kommunisere på. De mer nysgjerrige vil sikkert legge merke til at det mangler frakobling av domenehendelser utenfor applikasjonslaget - i den nåværende versjonen er de duplisert, og det er ingen full støtte for KonvoluttBlant annet er det ingen Frimerker. For disse og andre vil jeg invitere deg til å lese del II, der vi tar for oss temaet om å forene domenestrukturen til Symfony-applikasjoner i et mikrotjenestemiljø, og diskuterer den andre populære kommunikasjonsmetoden for mikrotjenester - denne gangen synkron, basert på REST API.

samarbeidsbanner

Relaterte artikler

Programvareutvikling

PHP 8.2: Hva er nytt?

Den nye versjonen av PHP er rett rundt hjørnet. Hvilke nye implementeringer bør du vite om? Sjekk denne artikkelen for å finne ut av det!

The Codest
Sebastian Luczak PHP Enhetsleder
Programvareutvikling

PHP Utvikling. Symfony-konsollkomponent - tips og triks

Denne artikkelen ble opprettet med sikte på å vise deg de mest nyttige og nyttige tipsene og triksene om Symfony Console Development.

The Codest
Sebastian Luczak PHP Enhetsleder

Abonner på vår kunnskapsbase og hold deg oppdatert på ekspertisen fra IT-sektoren.

    Om oss

    The Codest - Internasjonalt programvareutviklingsselskap med teknologisentre i Polen.

    Storbritannia - Hovedkvarter

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

    Polen - Lokale teknologisentre

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

      The Codest

    • Hjem
    • Om oss
    • Tjenester
    • Casestudier
    • Vet hvordan
    • Karriere
    • Ordbok

      Tjenester

    • Det rådgivende
    • Programvareutvikling
    • Backend-utvikling
    • Frontend-utvikling
    • Staff Augmentation
    • Backend-utviklere
    • Ingeniører i skyen
    • Dataingeniører
    • Annet
    • QA-ingeniører

      Ressurser

    • Fakta og myter om samarbeid med en ekstern programvareutviklingspartner
    • Fra USA til Europa: Hvorfor velger amerikanske oppstartsbedrifter å flytte til Europa?
    • Sammenligning av Tech Offshore Development Hubs: Tech Offshore Europa (Polen), ASEAN (Filippinene), Eurasia (Tyrkia)
    • Hva er de største utfordringene for CTO-er og CIO-er?
    • The Codest
    • The Codest
    • The Codest
    • Retningslinjer for personver
    • Vilkår for bruk av nettstedet

    Opphavsrett © 2025 av The Codest. Alle rettigheter forbeholdt.

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