window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versión: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster ya existe') } 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: Comunicación de Microservicios parte I - The Codest
The Codest
  • Quiénes somos
  • Servicios
    • Desarrollo de software
      • Desarrollo Frontend
      • Desarrollo backend
    • Staff Augmentation
      • Desarrolladores frontales
      • Desarrolladores de backend
      • Ingenieros de datos
      • Ingenieros de la nube
      • Ingenieros de control de calidad
      • Otros
    • Asesoramiento
      • Auditoría y consultoría
  • Industrias
    • Fintech y Banca
    • E-commerce
    • Adtech
    • Tecnología sanitaria
    • Fabricación
    • Logística
    • Automoción
    • IOT
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • Nuestro equipo
  • Case Studies
  • Saber cómo
    • Blog
    • Meetups
    • Seminarios en línea
    • Recursos
Carreras profesionales Póngase en contacto
  • Quiénes somos
  • Servicios
    • Desarrollo de software
      • Desarrollo Frontend
      • Desarrollo backend
    • Staff Augmentation
      • Desarrolladores frontales
      • Desarrolladores de backend
      • Ingenieros de datos
      • Ingenieros de la nube
      • Ingenieros de control de calidad
      • Otros
    • Asesoramiento
      • Auditoría y consultoría
  • Valor para
    • CEO
    • CTO
    • Gestor de entregas
  • Nuestro equipo
  • Case Studies
  • Saber cómo
    • Blog
    • Meetups
    • Seminarios en línea
    • Recursos
Carreras profesionales Póngase en contacto
Flecha atrás VOLVER
2022-06-28
Desarrollo de software

Symfony: Comunicación de Microservicios parte I

The Codest

Sebastian Luczak

PHP Jefe de Unidad

Lee la primera parte de nuestra serie PHP dedicada a la comunicación de microservicios en el framework Symfony y la forma más popular - la comunicación AMQP usando RabbitMQ.

La arquitectura moderna de las aplicaciones ha obligado a los desarrolladores a cambiar la forma de concebir la comunicación entre los distintos componentes de los sistemas informáticos. Antes el asunto era más sencillo: la mayoría de los sistemas se creaban como estructuras monolíticas conectadas entre sí por una red de conexiones de lógica empresarial. Mantener esas dependencias en un PHP proyecto fue un gran reto para Desarrolladores PHPy la creciente popularidad de las soluciones SaaS y el enorme aumento de la popularidad de nube servicios hizo que hoy oigamos hablar cada vez más de microservicios y modularidad de aplicaciones.

¿Cómo, creando microservicios independientes, podemos hacer que intercambien información entre sí?

Este artículo es el primero de una serie sobre comunicación de microservicios en Symfony y cubre la forma más popular - la comunicación AMQP usando RabbitMQ.

Objetivo

Crear dos aplicaciones independientes y lograr la comunicación entre ellas utilizando únicamente el Bus de Mensajes.

El concepto

Tenemos dos aplicaciones imaginarias e independientes:
* aplicación1que envía notificaciones por correo electrónico y SMS a los empleados
* aplicación2que permite gestionar el trabajo de los empleados y asignarles tareas.

Queremos crear un sistema moderno y sencillo mediante el cual la asignación de trabajo a un empleado en aplicación2 enviará una notificación al cliente utilizando aplicación1. A pesar de las apariencias, ¡esto es muy sencillo!

Preparación

Para el propósito de este artículo, utilizaremos la última versión de Symfony (versión 6.1 en el momento de escribir este artículo) y la última versión de PHP (8.1). En unos sencillos pasos crearemos un entorno Docker local con dos microservicios. Todo lo que necesitas es:
* un ordenador que funcione,
* instalado Docker + Entorno Docker Compose
* y un Symfony CLI y algo de tiempo libre.

Entorno de ejecución

Utilizaremos las capacidades de Docker como herramienta de virtualización y contenedorización de aplicaciones. Empecemos creando un árbol de directorios, un marco para dos Aplicaciones Symfonyy describir la infraestructura de nuestros entornos utilizando la herramienta docker-compose.yml archivo.

 cd ~
 mkdir microservicios-en-symfony
 cd microservicios-en-symfony
 symfony nueva app1
 symfony nueva app2
 tocar docker-compose.yml

Hemos creado dos directorios para dos aplicaciones Symfony distintas y hemos creado un directorio vacío docker-compose.yml para lanzar nuestro entorno.

Añadamos las siguientes secciones a docker-compose.yml file:

versión: '3.8

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

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

rabbitmq
containername: rabbitmq
imagen: rabbitmq:gestión
puertos:
- 15672:15672
- 5672:5672
entorno:
- RABBITMQDEFAULTUSER=usuario
- RABBITMQDEFAULT_PASS=contraseña

Fuente código disponible directamente: thecodest-co/microservices-in-symfony/blob/main/docker-compose.yml

Pero espera, ¿qué ha pasado aquí? Para aquellos que no estén familiarizados con Docker, el archivo de configuración anterior puede parecer enigmático, sin embargo su propósito es muy simple. Usando Docker Compose estamos construyendo tres "servicios":

  • app1: que es un contenedor para la primera aplicación Symfony
  • app2: que es el contenedor para la segunda aplicación Symfony
  • rabbitmq: la imagen de la aplicación RabbitMQ como capa intermedia de comunicación

Para que funcione correctamente, seguimos necesitando Dockerfile que son la fuente para construir las imágenes. Así que vamos a crearlos:

touch app1/Dockerfile
 touch app2/Dockerfile

Ambos archivos tienen exactamente la misma estructura y tienen el siguiente aspecto:

DE php:8.1

COPIAR --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPIAR . /app/
directorio de trabajo /app/

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

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

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

EJECUTAR docker-php-ext-install zip;

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

Código fuente disponible directamente: /thecodest-co/microservices-in-symfony/blob/main/app1/Dockerfile

El archivo anterior es utilizado por Docker Compose para construir un contenedor a partir de una imagen PHP 8.1 con Composer y la extensión AMQP instalada. Además, ejecuta el intepreter PHP en modo append para mantener el contenedor en ejecución en segundo plano.

Su árbol de directorios y archivos debería tener ahora el siguiente aspecto:

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

El primer microservicio Symfony

Empecemos por el aplicación1 y la primera aplicación.
En nuestro ejemplo, se trata de una aplicación que escucha y consume mensajes de la cola enviados por aplicación2 como se describe en los requisitos:

asignar un trabajo a un trabajador en aplicación2 enviará una notificación al cliente

Empecemos por añadir las librerías necesarias. AMQP es compatible de forma nativa con symfony/messenger extensión. Además, instalaremos monólogo/monolog para realizar un seguimiento de los registros del sistema y facilitar el análisis del comportamiento de las aplicaciones.

 cd app1/
 symfony composer req amqp ampq-messenger monolog

Tras la instalación, se añadió un archivo adicional en config/paquetes/messenger.yaml. Es un archivo de configuración para el componente Symfony Messenger y no necesitamos su configuración completa.
Sustitúyalo por el siguiente archivo YAML:

marco:
messenger:
# Descomente esto (y el transporte fallido a continuación) para enviar mensajes fallidos a este transporte para su posterior gestión.
# failure_transport: fallido

    transportes:
        # https://symfony.com/doc/current/messenger.html#transport-configuration
        mensajes_externos:
            dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
            opciones:
                auto_setup: false
                intercambio:
                    nombre: mensajes
                    type: direct
                    default_publish_routing_key: from_external
                colas:
                    messages:
                        binding_keys: [from_external]

Código fuente disponible directamente: thecodest-co/microservices-in-symfony/blob/main/app1/config/packages/messenger.yaml

Symfony Messenger se utiliza para la comunicación síncrona y asíncrona en aplicaciones Symfony. Soporta una variedad de transportao fuentes de verdad de la capa de transporte. En nuestro ejemplo, utilizamos la extensión AMQP que soporta el sistema de colas de eventos RabbitMQ.

La configuración anterior define un nuevo transporte denominado mensajes_externosque hace referencia al MESSENGER_TRANSPORT_DSN y define la escucha directa en mensajes en el Bus de Mensajes. En este punto, edite también el app1/.env y añada la dirección de transporte correspondiente.

"`env

(...)
MESSENGERTRANSPORTDSN=amqp://usuario:contraseña@rabbitmq:5672//messages
(...)
"
Después de preparar el framework de la aplicación y configurar las librerías, es hora de implementar la lógica de negocio. Sabemos que nuestra aplicación debe responder a la asignación de un trabajo a un trabajador. También sabemos que la asignación de un trabajo en theapp2system cambia el estado del trabajo. Así que vamos a crear un modelo que imita el cambio de estado y guardarlo en la rutaapp1/Message/StatusUpdate.php`:
imagen
 {
public function __construct(cadena protegida $status){}

public function getStatus(): cadena
{
    return $this->estado;
}

}

Código fuente disponible directamente: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Message/StatusUpdate.php

Todavía necesitamos una clase que implemente la lógica de negocio cuando nuestro microservicio reciba el evento anterior de la cola. Así que vamos a crear una clase Gestor de mensajes en el app1/Handler/StatusUpdateHandler.php camino:

imagen
 use PsrLogLoggerInterface;
use SymfonyComponentMessengerAttributeAsMessageHandler;

[AsMessageHandler]

class StatusUpdateHandler
{
función pública __construct(
protected LoggerInterface $logger,
) {}

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

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

    // el resto de la lógica de negocio, es decir, el envío de correo electrónico al usuario
    // $this->emailService->email()
}

}

Código fuente disponible directamente: /thecodest-co/microservices-in-symfony/blob/main/app1/src/Handler/StatusUpdateHandler.php

PHP facilitan mucho las cosas y hacen que, en este caso concreto, no tengamos que preocuparnos del autocableado ni de la declaración de servicios. Nuestro microservicio para gestionar eventos de dominio está listo, es hora de pasar a la segunda aplicación.

Segundo microservicio Symfony

Echaremos un vistazo a la aplicación2 y el segundo Aplicación Symfony. Nuestra idea es enviar un mensaje a la cola cuando a un trabajador se le asigna una tarea en el sistema. Así que vamos a hacer una configuración rápida de AMQP y conseguir que nuestro segundo microservicio empiece a publicar StatusUpdate al bus de mensajes.

La instalación de las bibliotecas es exactamente igual que para la primera aplicación.

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

Asegurémonos de que el app2/.env contiene una entrada DSN válida para RabbitMQ:

(...)
 MESSENGER_TRANSPORT_DSN=amqp://usuario:contraseña@rabbitmq:5672//mensajes
 (...)

Todo lo que queda es configurar Symfony Messenger en el archivo app2/config/paquetes/messenger.yaml file:

marco:
messenger:
# Descomente esto (y el transporte fallido a continuación) para enviar mensajes fallidos a este transporte para su posterior gestión.
# failure_transport: fallido

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

    enrutamiento:
        # Enruta tus mensajes a los transportes
        AppMessageStatusUpdate': async

Como puede ver, esta vez la definición de transporte apunta directamente a async y define el enrutamiento en forma de envío de nuestro StatusUpdate al DSN configurado. Esta es la única área de configuración, sólo queda crear la capa lógica y de implementación de la cola AMQP. Para ello crearemos el gemelo StatusUpdateHandler y StatusUpdate clases en aplicación2.

imagen
 use PsrLogLoggerInterface;
use SymfonyComponentMessengerAttributeAsMessageHandler;

[AsMessageHandler]

class StatusUpdateHandler
{
función pública __construct(
private readonly LoggerInterface $logger,
) {}

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

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

    ## lógica de negocio, es decir, el envío de notificación interna o la cola de algunos otros sistemas
}

}
imagen
 {
public function __construct(cadena protegida $status){}

public function getStatus(): cadena
{
    return $this->estado;
}

}


Código fuente disponible directamente: /thecodest-co/microservices-in-symfony/blob/main/app2/src/Message/StatusUpdate.php

Finalmente, todo lo que hay que hacer es crear una forma de enviar un mensaje al Bus de Mensajes. Crearemos un simple Comando Symfony por esto:

imagen
use SymfonyComponentConsoleAttributeAsCommand;
use SymfonyComponentConsoleCommandComando;
use SymfonyComponentConsoleInputInterface;
use SymfonyComponentConsoleOutputOutputInterface;
use SymfonyComponentMessengerMessageBusInterface;

[AsCommand(

nombre: "app:enviar"

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

protected function ejecutar(InputInterface $input, OutputInterface $output): int
{
    $status = "Trabajador X asignado a Y";

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

    return Command::SUCCESS;
}

}

Gracias a Inyección de dependencia podemos utilizar una instancia de Interfaz MessageBus en nuestro Comando y enviar un StatusUpdate mensaje a través del enviar() a nuestra cola. Además, también utilizamos PHP Atributos aquí.

Eso es todo - todo lo que queda es ejecutar nuestro entorno Docker Compose y ver cómo se comportan nuestras aplicaciones.

Ejecución del entorno y pruebas

Con Docker Compose los contenedores con nuestras dos aplicaciones se construirán y ejecutarán como instancias separadas, la única capa de middleware será la aplicación rabbitmq y nuestra implementación del bus de mensajes.

Desde el directorio raíz del proyecto, vamos a ejecutar los siguientes comandos:

cd ../ # asegúrate de que estás en el directorio principal.
 docker-compose up --build -d

Este comando puede llevar algún tiempo, ya que construye dos contenedores separados con PHP 8.1 + AMQP y extrae la imagen de RabbitMQ. Tenga paciencia. Después de que las imágenes estén construidas, puedes ejecutar nuestro comando desde aplicación2 y enviar algunos mensajes a una cola.

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

Puedes hacerlo tantas veces como puedas. Mientras no haya consumidor sus mensajes no serán procesados. En cuanto encienda el aplicación1 y consumir todos los mensajes que mostrarán en tu pantalla.

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

El completo código fuente junto con el README se puede encontrar en nuestro repositorio público The Codest Github

Resumen

Symfony, con sus bibliotecas y herramientas, permite un enfoque rápido y eficaz para el desarrollo de aplicaciones modernas. aplicaciones web. Con unos pocos comandos y unas pocas líneas de código somos capaces de crear un moderno sistema de comunicación entre aplicaciones. Symfony, al igual que PHPes ideal para desarrollo de aplicaciones web y gracias a su ecosistema y a su facilidad de implantación, este ecosistema logra algunos de los mejores indicadores de tiempo de comercialización.

Sin embargo, rápido no siempre significa bueno - en el ejemplo anterior presentamos la forma más simple y rápida de comunicación. Lo que los más curiosos seguramente notarán es que hay una falta de desconexión de eventos de dominio fuera de la capa de aplicación - en la versión actual están duplicados, y no hay soporte completo para Sobreentre otros no hay Sellos. Para esos y otros, te invito a leer la Parte II, donde cubriremos el tema de la unificación de la estructura de dominios de las aplicaciones Symfony en un entorno de microservicios, y discutiremos el segundo método popular de comunicación de microservicios - esta vez síncrono, basado en la API REST.

bandera de cooperación

Artículos relacionados

Desarrollo de software

PHP 8.2: ¿Qué hay de nuevo?

La nueva versión de PHP está a la vuelta de la esquina. ¿Cuáles son las nuevas implementaciones que debe conocer? Consulte este artículo para saberlo.

The Codest
Sebastian Luczak PHP Jefe de Unidad
Desarrollo de software

PHP Desarrollo. Symfony Console Component - Trucos y consejos

Este artículo fue creado con el objetivo de mostrarte los consejos y trucos más útiles y recuperables sobre el desarrollo de la consola Symfony.

The Codest
Sebastian Luczak PHP Jefe de Unidad

Suscríbase a nuestra base de conocimientos y manténgase al día de la experiencia del sector informático.

    Quiénes somos

    The Codest - Empresa internacional de desarrollo de software con centros tecnológicos en Polonia.

    Reino Unido - Sede central

    • Oficina 303B, 182-184 High Street North E6 2JA
      Londres, Inglaterra

    Polonia - Centros tecnológicos locales

    • Parque de oficinas Fabryczna, Aleja
      Pokoju 18, 31-564 Cracovia
    • Embajada del Cerebro, Konstruktorska
      11, 02-673 Varsovia, Polonia

      The Codest

    • Inicio
    • Quiénes somos
    • Servicios
    • Case Studies
    • Saber cómo
    • Carreras profesionales
    • Diccionario

      Servicios

    • Asesoramiento
    • Desarrollo de software
    • Desarrollo backend
    • Desarrollo Frontend
    • Staff Augmentation
    • Desarrolladores de backend
    • Ingenieros de la nube
    • Ingenieros de datos
    • Otros
    • Ingenieros de control de calidad

      Recursos

    • Hechos y mitos sobre la cooperación con un socio externo de desarrollo de software
    • De EE.UU. a Europa: ¿Por qué las startups estadounidenses deciden trasladarse a Europa?
    • Comparación de los polos de desarrollo de Tech Offshore: Tech Offshore Europa (Polonia), ASEAN (Filipinas), Eurasia (Turquía)
    • ¿Cuáles son los principales retos de los CTO y los CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Condiciones de uso del sitio web

    Copyright © 2025 por The Codest. Todos los derechos reservados.

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