/demoMessenger

Servicio asíncrono basado en mensajes (con el gestor RabbitMQ)

Primary LanguagePHPMIT LicenseMIT

logo UPM MiW: Ejemplo de servicios asíncronos

Minimum PHP Version MIT license

📬 Ejemplo de servicio asíncrono basado en mensajes (con el gestor RabbitMQ)

En este ejemplo se implementan dos servicios asíncronos que se comunican a través de un gestor de colas de mensajes. El gestor de mensajes (message broker) empleado es RabbitMQ, que proporciona un sistema de negociación de mensajes de código abierto. Por su parte, los servicios utilizan el protocolo AMQP para conectarse con el gestor de mensajes, y además ofrecen una interfaz para poder realizar dos sencillas operaciones:

  • Enviar una notificación a la cola
  • Consumir una notificación de la cola

En el ejemplo, cada notificación (en formato JSON) contiene un texto y una lista de direcciones de correo electrónico similar a:

{
  "textMessage": "Message text",
  "users": [
    "foo@example.com",
    "bar@example.com"
  ]
}

 

img

📨 Servicio de envío de notificaciones (productor, puerto 8000)

El servicio de envío de notificaciones actúa como productor: construye un mensaje que contiene la notificación y lo entrega al intermediario, es decir, lo envía a la cola de mensajes. El mensaje permanecerá en la cola a la espera de ser consumido por algún servicio.

img

En el ejemplo la cola se ha denominado messages_high. Dentro de RabbittMQ, cuando un productor desea encolar un nuevo mensaje, lo que hace es enviarlo a un intercambiador (exchange), que se comporta como agente de enrutamiento. Este intercambiador (high en el ejemplo) es el responsable del envío de los mensajes a las diferentes colas de acuerdo a sus reglas internas.

📩 Servicio consumidor de notificaciones (consumidor, puerto 8080)

El servicio consumir notificación actúa como consumidor: se conecta al gestor de mensajes, y, si hay algún mensaje en la cola, lo recoge. En este ejemplo, cuando se procesa un mensaje simplemente se simula el envío de un texto a la lista de destinatarios de la notificación.

img

En esta implementación, tanto productor como consumidor utilizan un cuarto servicio (denominado php_fpm) que proporciona el intérprete FPM (FastCGI Process Manager) de PHP.


🚀 Despliegue de los servicios

Para acceder a estas operaciones se ha desarrollado una API que ha sido documentada a través del esquema OpenAPI 3.0. Esta especificación se ha elaborado empleando el editor Swagger. Adicionalmente se incluye la interfaz de usuario (Swagger-UI) de esta fenomenal herramienta que permite realizar pruebas interactivas de manera completa y elegante.

Para desplegar el proyecto empleando Docker, basta con ejecutar el siguiente comando desde el directorio raíz del proyecto:

docker compose up -d

La primera vez que se generan las imágenes pueden ser algo lenta, debido a la instalación de los diferentes componentes requeridos por la aplicación.

Desde la consola del sistema anfitrión se puede obtener la lista de los contenedores desplegados empleando:

docker ps --format "{{.Names}}: Ports [{{.Ports}}]"

Una vez desplegado el proyecto, se podrá acceder a la interfaz de usuario de la especificación a través de http://localhost:8000/api-docs/index.html. Además, también se podrá acceder a la herramienta RabbitMQ Management en http://localhost:15672/ (usuario guest y password guest).

📈 Accediendo a la cola

La cola de mensajes se crea en el instante en el que se recibe el primer mensaje. El estado de las diferentes colas en el broker se puede observar a través de la dirección http://localhost:15672/#/queues. Si se ha enviado algún mensaje aparecerá una cola (denominada messages_high), y se pueden examinar todos los detalles de la misma en tiempo real (la interfaz se actualiza automáticamente por defecto cada 5 segundos).

Aparte de utilizar la interfaz de la API, también es posible consumir los mensajes a través de la consola de comandos (con mayor nivel de detalle). Para ello se deberán ejecutar los siguientes comandos:

docker exec -it -u dev php_fpm bash
cd ./aos
bin/console -vvv --limit=1 messenger:consume

🛑 Deteniendo los servicios

Como curiosidad, si se desea acceder a los detalles internos del funcionamiento de la aplicación (implementada sobre el framework PHP Symfony) se puede acceder a la dirección http://localhost:8000/_profiler.

Finalmente, para detener la ejecución de los contenedores desde el anfitrión se ejecutará el comando:

docker compose down --rmi local -v