PHP asincrónico para respaldar la estabilidad de su aplicación
Asincrónico — Ocurre que algunas partes del sistema o integraciones externas no están disponibles o tienen un tiempo de ejecución prolongado.
Al igual que un panadero no se para y espera a que se hornee el pan, mientras tanto puede preparar otros nuevos, lo mismo ocurre con los usuarios de nuestros sistemas.
- Podemos permitir que el usuario finalice el registro y envíe correo electrónico de forma asincrónica.
- Podemos generar el informe de forma asincrónica y enviar el enlace de descarga una vez finalizado.
- Podemos ejecutar integraciones externas de forma asincrónica, por lo que la indisponibilidad del servicio externo no tiene ningún efecto en el usuario final.
Flujos
Es importante conocer sobre manejo de eventos, analizamos cómo separar los flujos entre sí mediante eventos. Y saber qué flujos tenemos en el sistema, ya que es el flujo el que nos da pistas, si debemos hacerlo asincrónico.
Flujo de registro de usuario
Continuando con el ejemplo de la publicación sobre Manejo de eventos.
Para registrar un usuario, Main Flow estaría creando un usuario y guardándolo en la base de datos.
Los subflujos por otro lado serían:
- Envío de correo electrónico de bienvenida o confirmación
- Creación de registros de auditoría sobre el registro de usuarios.
- Sincronización del usuario registrado con el servicio externo (Integración externa)
Gracias a que definimos claramente qué flujos tenemos en un escenario dado, podemos decidir cuál de ellos puede ejecutarse de forma asincrónica.
Definamos qué problemas podemos resolver eligiendo ejecutar los flujos de forma asincrónica:
1. Llamar al servicio externo puede llevar más tiempo.
El servicio con el que nos integramos puede tener mucho tráfico o algunos problemas de rendimiento.
Al llamar a este código de forma asincrónica, permitimos que el usuario final finalice el registro sin problemas. En segundo lugar, nos permite liberar recursos como la memoria, ya que la solicitud termina de inmediato.
2. El servicio externo puede estar inactivo.
Puede caer porque había mucho tráfico, o un error que hizo que la API fallara o simplemente el proceso de implementación la está poniendo en modo de mantenimiento.
Hacer que el código sea asincrónico nos permite finalizar el registro con éxito, sin importar lo que suceda en el lado de terceros.
3. Podemos terminar en un estado inconsistente.
¿Qué pasa si el correo electrónico se envió con éxito, pero la llamada al servicio externo falló?
Si revertimos la transacción de la base de datos, fallamos el registro, sin embargo, se informará al usuario sobre el registro exitoso.
Si confirmamos la transacción de la base de datos, el servicio externo no tendrá información sobre el usuario.
Ejecutar el código de forma asincrónica nos permite tener éxito en el registro y llamar al servicio externo más tarde, cuando esté en funcionamiento. Entonces siempre terminamos en un estado consistente.
Hacer que el flujo sea asincrónico
Para hacer que un flujo específico sea asíncrono, marcamos Handler como Asynchronous.
Puede estar familiarizado con marcar el evento como asincrónico. Este es un enfoque de todo o nada.
Ecotone permite que los manipuladores se marquen como asíncronos. Esto abre la posibilidad para que el desarrollador decida qué controladores específicos deben ejecutarse de forma asincrónica para un evento determinado.
La anotación “asincrónico” permite que un controlador específico se ejecute de forma asincrónica utilizando el canal de mensajes “asynchronous_messages”.
El canal de mensajes permite abstraer la implementación específica del mecanismo de entrega de mensajes, por lo que su código se limpia de problemas de infraestructura y puede cambiarlo a uno diferente sin tocar el código comercial.
Ahora tenemos que elegir el módulo asincrónico.
En este escenario particular, usaremos el módulo RabbitMQ.
Seguimiento del proceso de instalación:
Y registremos nuestro canal de mensajes para RabbitMQ.
<?php class Configuration { #[ServiceContext] public function enableRabbitMQ() { return AmqpBackedMessageChannelBuilder::create("asynchronous_messages"); } }
Puede cambiar fácilmente la implementación del canal de mensajes o hacer uso de diferentes canales para diferentes controladores.
Publiquemos el evento de la misma manera que lo hicimos para el código síncrono.
<?php use Ecotone\Modelling\EventBus; class PersonRegistrationService { public function __construct(private UserRepository $userRepository, private EventBus $event) {} public function registerUser($registerPersonData) { $person = new Person($registerPersonData); $this->userRepository->save($person); $this->event->publish(new PersonWasRegistered($person->getPersonId())); } }
Ahora puede ejecutar el consumidor para manejar el evento.
El consumidor se registra automáticamente para nosotros y consumirá el mensaje del canal de mensajes “asynchronous_messages”.
Symfony:
bin/console ecotone:run asynchronous_messages -vvv
Laravel:
artisan ecotone:run orders -vvv
Resumen
Hacer el código de forma asincrónica es sencillo en Ecotone.
Esto muestra uno de los principios de Ecotone. Su código quedará limpio de problemas de infraestructura, por lo que puede concentrarse en la funcionalidad comercial y mantener su código limpio.