window.pipedriveLeadboosterConfig = { bas: 'leadbooster-chat.pipedrive.com', företagId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(funktion () { var w = fönster if (w.LeadBooster) { console.warn('LeadBooster finns redan') } annars { w.LeadBooster = { q: [], on: funktion (n, h) { this.q.push({ t: "o", n: n, h: h }) }, trigger: funktion (n) { this.q.push({ t: 't', n: n }) }, } } })() Symfony: Kommunikation av mikrotjänster del I - The Codest
Codest
  • Om oss
  • Tjänster
    • Utveckling av programvara
      • Frontend-utveckling
      • Backend-utveckling
    • Staff Augmentation
      • Frontend-utvecklare
      • Backend-utvecklare
      • Dataingenjörer
      • Ingenjörer inom molntjänster
      • QA-ingenjörer
      • Övriga
    • Det rådgivande
      • Revision och rådgivning
  • Industrier
    • Fintech & bankverksamhet
    • E-commerce
    • Adtech
    • Hälsoteknik
    • Tillverkning
    • Logistik
    • Fordon
    • IOT
  • Värde för
    • VD OCH KONCERNCHEF
    • CTO
    • Leveranschef
  • Vårt team
  • Fallstudier
  • Vet hur
    • Blogg
    • Möten
    • Webbinarier
    • Resurser
Karriär Ta kontakt med oss
  • Om oss
  • Tjänster
    • Utveckling av programvara
      • Frontend-utveckling
      • Backend-utveckling
    • Staff Augmentation
      • Frontend-utvecklare
      • Backend-utvecklare
      • Dataingenjörer
      • Ingenjörer inom molntjänster
      • QA-ingenjörer
      • Övriga
    • Det rådgivande
      • Revision och rådgivning
  • Värde för
    • VD OCH KONCERNCHEF
    • CTO
    • Leveranschef
  • Vårt team
  • Fallstudier
  • Vet hur
    • Blogg
    • Möten
    • Webbinarier
    • Resurser
Karriär Ta kontakt med oss
Pil tillbaka GÅ TILLBAKA
2022-06-28
Utveckling av programvara

Symfony: Mikrotjänstkommunikation del I

Codest

Sebastian Luczak

PHP Enhetschef

Läs den första delen av vår PHP-serie som handlar om kommunikation mellan mikrotjänster i Symfony-ramverket och det mest populära sättet - AMQP-kommunikation med RabbitMQ.

Modern applikationsarkitektur har tvingat utvecklare att ändra sitt sätt att tänka kring kommunikationen mellan olika komponenter i IT-system. En gång i tiden var det enklare - de flesta system skapades som monolitiska strukturer som var kopplade till varandra genom ett nätverk av affärslogiska kopplingar. Att underhålla sådana beroenden i en PHP projekt var en stor utmaning för PHP utvecklareoch den växande populariteten för SaaS-lösningar och den enorma ökningen av populariteten för moln att vi idag hör mer och mer om mikrotjänster och applikationsmodularitet.

Hur kan vi genom att skapa oberoende mikrotjänster få dem att utbyta information med varandra?

Denna artikel är den första i en serie inlägg om kommunikation med mikrotjänster i Symfony och den täcker det mest populära sättet - AMQP-kommunikation med hjälp av RabbitMQ.

Mål

Att skapa två oberoende applikationer och uppnå kommunikation mellan dem med hjälp av endast Message Bus.

Konceptet

Vi har två, imaginära, oberoende applikationer:
* app1: som skickar e-post- och SMS-meddelanden till anställda
* app2: som gör att du kan hantera medarbetarnas arbete och tilldela dem uppgifter.

Vi vill skapa ett modernt och enkelt system där tilldelningen av arbete till en anställd i app2 kommer att skicka ett meddelande till kunden med hjälp av app1. Trots att det ser ut så är detta mycket enkelt!

Förberedelser

I den här artikeln använder vi den senaste versionen av Symfony (version 6.1 i skrivande stund) och den senaste versionen av PHP (8.1). I några mycket enkla steg skapar vi en fungerande lokal Docker-miljö med två mikrotjänster. Allt du behöver är:
* en fungerande dator,
* installerade Docker + Docker Compose-miljö
* och en lokalt konfigurerad Symfony CLI och lite fritid.

Körtidsmiljö

Vi kommer att använda Dockers kapacitet som ett verktyg för virtualisering av applikationer och containerisering. Låt oss börja med att skapa ett katalogträd, ett ramverk för två Symfony-applikationeroch beskriva infrastrukturen i våra miljöer med hjälp av docker-compose.yml fil.

 cd ~
 mkdir microservices-in-symfony
 cd mikrotjänster-i-symfony
 symfony ny app1
 symfony ny app2
 tryck på docker-compose.yml

Vi har skapat två kataloger för två separata Symfony-applikationer och skapat en tom docker-compose.yml filen för att starta vår miljö.

Låt oss lägga till följande avsnitt i docker-compose.yml file:

version: '3.8'

tjänster:
app1:
containername: app1
bygga: app1/.
restart: på fel
envfile: app1/.env
miljö:
APPNAME: app1
tty: sant
stdinopen: true

app2:
containername: app2
bygga: app2/.
omstart: vid misslyckande
envfile: app2/.env
miljö: app2/.env
APPNAME: app2
tty: sant
stdinopen: true

rabbitmq:
containername: rabbitmq
bild: rabbitmq:management
portar:
- 15672:15672
- 5672:5672
environment (miljö):
- RABBITMQDEFAULTUSER=användare
- RABBITMQDEFAULT_PASS=lösenord

Källa kod direkt tillgängliga: thecodest-co/microservices-in-symfony/blob/main/docker-compose.yml

Men vänta, vad hände här? För den som inte är bekant med Docker kan konfigurationsfilen ovan verka gåtfull, men dess syfte är mycket enkelt. Med hjälp av Docker Compose bygger vi tre "tjänster":

  • app1: som är en behållare för den första Symfony-applikationen
  • app2: som är behållaren för den andra Symfony-applikationen
  • rabbitmq: applikationsbilden RabbitMQ som ett middleware-lager för kommunikation

För korrekt drift behöver vi fortfarande Dockerfil filer som är källan för att bygga bilderna. Så låt oss skapa dem:

 touch app1/Dockerfile
 tryck på app2/Dockerfile

Båda filerna har exakt samma struktur och ser ut på följande sätt:

FRÅN php:8.1

COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
KOPIERA . /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 &&
installera-php-utvidgningar amqp

KÖR apt-get uppdatering
&& apt-get install -y libzip-dev wget --no-install-recommends
&& apt-get rensa
&& 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"

Källkod tillgänglig direkt: /thecodest-co/microservices-in-symfony/blob/main/app1/Dockerfile

Ovanstående fil används av Docker Compose för att bygga en container från en PHP 8.1-avbildning med Composer och AMQP-tillägget installerat. Dessutom kör den PHP intepreter i append-läge för att hålla behållaren igång i bakgrunden.

Ditt katalog- och filträd bör nu se ut på följande sätt:

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

Den första Symfony-mikrotjänsten

Låt oss börja med app1 och den första applikationen.
I vårt exempel är det en applikation som lyssnar på och konsumerar meddelanden från kön som skickas av app2 enligt beskrivningen i kraven:

tilldela ett jobb till en arbetare i app2 kommer att skicka ett meddelande till klienten

Låt oss börja med att lägga till de nödvändiga biblioteken. AMQP har inbyggt stöd för symfony/messenger förlängning. Vi kommer dessutom att installera monolog/monolog för att hålla reda på systemloggar för enklare analys av programbeteende.

 cd app1/
 symfony composer req amqp ampq-messenger monolog

Efter installationen lades en ytterligare fil till under config/packages/messenger.yaml. Det är en konfigurationsfil för Symfony Messenger-komponenten och vi behöver inte dess fullständig konfiguration.
Ersätt den med YAML-filen nedan:

ramverk:
messenger:
# Kommentera bort detta (och failed transport nedan) för att skicka misslyckade meddelanden till denna transport för senare hantering.
# fel_transport: misslyckades

    transporter:
        # https://symfony.com/doc/current/messenger.html#transport-configuration
        externa_meddelanden:
            dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
            alternativ:
                auto_setup: false
                exchange:
                    namn: meddelanden
                    typ: direkt
                    default_publish_routing_key: från_extern
                köer:
                    messages:
                        bindande_nycklar: [från_extern]

Källkod tillgänglig direkt: thecodest-co/microservices-in-symfony/blob/main/app1/config/packages/messenger.yaml

Symfony Messenger används för synkron och asynkron kommunikation i Symfony-applikationer. Den stöder en mängd olika transportereller sanningskällor för transportlagret. I vårt exempel använder vi AMQP-tillägget som stöder händelsekösystemet RabbitMQ.

Ovanstående konfiguration definierar en ny transport med namnet externa_meddelanden, som hänvisar till BUDBÄRARE_TRANSPORT_DSN miljövariabel och definierar direkt lyssning på meddelanden kanal i meddelandebussen. Vid denna punkt redigerar du också app1/.env filen och lägg till lämplig transportadress.

"`env

(...)
MESSENGERTRANSPORTDSN=amqp://user:password@rabbitmq:5672//messages
(...)
"
Efter att ha förberett applikationsramverket och konfigurerat biblioteken är det dags att implementera affärslogiken. Vi vet att vår applikation måste svara på tilldelningen av ett jobb till en arbetare. Vi vet också att om vi tilldelar ett jobb iapp2systemet ändras statusen för jobbet. Så låt oss skapa en modell som efterliknar statusändringen och spara den i sökvägenapp1/Message/StatusUpdate.php`:
bild
 {
public function __construct(protected string $status){}

publik funktion getStatus(): sträng
{
    return $this->status;
}

}

Källkod tillgänglig direkt: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Message/StatusUpdate.php

Vi behöver fortfarande en klass som kommer att implementera affärslogiken när vår mikrotjänst får ovanstående händelse från kön. Så låt oss skapa en Meddelandehanterare i app1/Handler/StatusUpdateHandler.php väg:

bild
 använd PsrLogLoggerInterface;
använd SymfonyComponentMessengerAttributeAsMessageHandler;

[AsMessageHandler]

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

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

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

    // resten av affärslogiken, dvs. skicka e-post till användaren
    // $this->emailService->email()
}

}

Källkod tillgänglig direkt: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Handler/StatusUpdateHandler.php

PHP attribut gör saker och ting mycket enklare och innebär att vi i det här fallet inte behöver oroa oss för autowiring eller servicedeklaration. Vår mikrotjänst för hantering av domänhändelser är klar, det är dags att gå vidare till den andra applikationen.

Andra Symfony-mikrotjänsten

Vi kommer att ta en titt på app2 katalog och den andra Symfony-applikation. Vår idé är att skicka ett meddelande till kön när en arbetare tilldelas en uppgift i systemet. Så låt oss göra en snabb konfiguration av AMQP och få vår andra mikrotjänst att börja publicera Statusuppdatering händelser till meddelandebussen.

Installationen av biblioteken går till på exakt samma sätt som för den första applikationen.

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

Låt oss se till att app2/.env filen innehåller en giltig DSN-post för RabbitMQ:

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

Allt som återstår är att konfigurera Symfony Messenger i app2/config/packages/messenger.yaml file:

ramverk:
messenger:
# Kommentera bort detta (och failed transport nedan) för att skicka misslyckade meddelanden till denna transport för senare hantering.
# fel_transport: misslyckades

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

    routing:
        # Routa dina meddelanden till transporterna
        'AppMessageStatusUpdate': async

Som du kan se pekar transportdefinitionen den här gången direkt till asynkron och definierar routing i form av att vi skickar våra Statusuppdatering meddelande till det konfigurerade DSN:et. Detta är det enda konfigurationsområdet, allt som återstår är att skapa logik- och implementeringslagret för AMQP-kön. För detta kommer vi att skapa tvillingen StatusUppdateringsHandler och Statusuppdatering klasser i app2.

bild
 använd PsrLogLoggerInterface;
använd SymfonyComponentMessengerAttributeAsMessageHandler;

[AsMessageHandler]

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

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

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

    ## affärslogik, dvs. skicka intern avisering eller köa till något annat system
}

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

publik funktion getStatus(): sträng
{
    return $this->status;
}

}


Källkod tillgänglig direkt: /thecodest-co/microservices-in-symfony/blob/main/app2/src/Message/StatusUpdate.php

Slutligen återstår det bara att skapa ett sätt att skicka ett meddelande till meddelandebussen. Vi kommer att skapa en enkel Symfony-kommando för detta:

bild
använd SymfonyComponentConsoleAttributeAsCommand;
använd SymfonyComponentConsoleCommandCommand;
använd SymfonyComponentConsoleInputInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
använd SymfonyComponentMessengerMessageBusInterface;

[AsCommand(

namn: "app:skicka"

)]
klass SendStatusCommand utökar Kommando
{
public function construct(private readonly MessageBusInterface $messageBus, string $name = null)
{
parent::construct($name);
}

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

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

    return Command::SUCCESS;
}

}

Tack till Injektion av beroenden kan vi använda en instans av MessageBus-gränssnitt i vårt Command och skicka ett Statusuppdatering meddelande via skicka() metod till vår kö. Dessutom använder vi också PHP-attribut här.

Det var allt - nu återstår bara att köra vår Docker Compose-miljö och se hur våra applikationer beter sig.

Kör miljön och testa

Med Docker Compose kommer containrarna med våra två applikationer att byggas och köras som separata instanser, det enda middleware-lagret kommer att vara rabbitmq container och vår implementering av Message Bus.

Från projektets rotkatalog kör vi följande kommandon:

cd ../ # se till att du är i huvudkatalogen
 docker-compose up --build -d

Det här kommandot kan ta lite tid, eftersom det bygger två separata behållare med PHP 8.1 + AMQP och drar RabbitMQ-bilden. Ha lite tålamod. När avbildningarna har byggts kan du starta vårt kommando från app2 och skicka några meddelanden på en kö.

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

Du kan göra det hur många gånger som helst. Så länge det inte finns någon konsument kommer dina meddelanden inte att behandlas. Så snart du startar upp app1 och konsumera alla meddelanden som de visar på din skärm.

docker exec -it app1 php bin/console messenger:consume -vv externa_meddelanden
bild

Den kompletta källkod tillsammans med README finns i vårt offentliga arkiv The Codest Github

Sammanfattning

Symfony med sina bibliotek och verktyg möjliggör ett snabbt och effektivt tillvägagångssätt för att utveckla moderna webbapplikationer. Med några få kommandon och några rader kod kan vi skapa ett modernt kommunikationssystem mellan applikationer. Symfony, precis som PHP, är idealisk för utveckla webbapplikationer och tack vare sitt ekosystem och enkla implementering uppnår detta ekosystem några av de bästa indikatorerna för tid till marknad.

Men snabbt betyder inte alltid bra - i exemplet ovan presenterade vi det enklaste och snabbaste sättet att kommunicera. Vad den mer nyfikne säkert kommer att märka är att det saknas en frånkoppling av domänhändelser utanför applikationslagret - i den nuvarande versionen dupliceras de, och det finns inget fullt stöd för Kuvertbland annat finns det ingen Frimärken. För dessa och andra inbjuder jag dig att läsa del II, där vi kommer att täcka ämnet att förena domänstrukturen för Symfony-applikationer i en mikrotjänstmiljö och diskutera den andra populära kommunikationsmetoden för mikrotjänster - den här gången synkron, baserad på REST API.

samarbetsbanner

Relaterade artiklar

Utveckling av programvara

PHP 8.2: Vad är nytt?

Den nya versionen av PHP är precis runt hörnet. Vilka är de nya implementeringar som du bör känna till? Kolla in den här artikeln för att ta reda på det!

Codest
Sebastian Luczak PHP Enhetschef
Utveckling av programvara

PHP utveckling. Symfony konsolkomponent - tips och tricks

Den här artikeln skapades i syfte att visa dig de mest användbara och hämta tips och tricks om Symfony Console Development.

Codest
Sebastian Luczak PHP Enhetschef

Prenumerera på vår kunskapsbas och håll dig uppdaterad om expertisen från IT-sektorn.

    Om oss

    The Codest - Internationellt mjukvaruutvecklingsföretag med teknikhubbar i Polen.

    Förenade kungariket - Huvudkontor

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

    Polen - Lokala tekniknav

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

      Codest

    • Hem
    • Om oss
    • Tjänster
    • Fallstudier
    • Vet hur
    • Karriär
    • Ordbok

      Tjänster

    • Det rådgivande
    • Utveckling av programvara
    • Backend-utveckling
    • Frontend-utveckling
    • Staff Augmentation
    • Backend-utvecklare
    • Ingenjörer inom molntjänster
    • Dataingenjörer
    • Övriga
    • QA-ingenjörer

      Resurser

    • Fakta och myter om att samarbeta med en extern partner för mjukvaruutveckling
    • Från USA till Europa: Varför väljer amerikanska startup-företag att flytta till Europa?
    • Jämförelse av Tech Offshore Development Hubs: Tech Offshore Europa (Polen), ASEAN (Filippinerna), Eurasien (Turkiet)
    • Vilka är de största utmaningarna för CTO:er och CIO:er?
    • Codest
    • Codest
    • Codest
    • Privacy policy
    • Användarvillkor för webbplatsen

    Copyright © 2025 av The Codest. Alla rättigheter reserverade.

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