¿Qué es la concurrencia?
Cuando ejecutas en serie varios procesos que no dependen entre sí, como solicitudes a varias APIs externas o agregaciones en la base de datos, el tiempo total es la suma de los tiempos de cada proceso. Si los ejecutas de forma concurrente, el tiempo total se reduce al tiempo del proceso más lento. La fachadaConcurrency de Laravel ofrece una API sencilla para lograr esa ejecución concurrente.
La fachada
Concurrency se introdujo en Laravel 11 y sigue disponible en Laravel 13.
Su driver por defecto usa procesos PHP hijos, por lo que funciona sin necesidad de paquetes adicionales.Cómo funciona
La fachadaConcurrency serializa los closures recibidos, los envía a un comando Artisan oculto y los ejecuta en procesos PHP separados.
Cuando cada proceso termina, se serializa el valor devuelto y se retorna al proceso padre.
Hay tres drivers disponibles.
| Driver | Descripción |
|---|---|
process | Por defecto. Lanza procesos PHP hijos. Funciona también en solicitudes web |
fork | Requiere el paquete spatie/fork. Como hace fork del proceso, solo funciona en CLI, pero es rápido |
sync | No ejecuta en paralelo, sino en secuencia. Adecuado para pruebas |
Uso básico
Concurrency::run()
Al pasar un array de closures arun(), se ejecutan concurrentemente.
El valor devuelto es un array con los valores retornados por cada closure.
Especificar el driver
Si quieres usar un driver específico, indícalo con el métododriver().
default.
Uso del driver fork
El driverfork es más rápido que process, pero solo puede usarse en un entorno CLI de PHP (comandos Artisan o workers de cola).
No puede usarse dentro de una solicitud web.
Antes de utilizarlo, instala el paquete spatie/fork.
Sin recibir resultados: Concurrency::defer()
Si no te interesa el resultado del proceso y quieres ejecutarlo en segundo plano después de haber devuelto la respuesta HTTP, usa el métododefer().
defer() los closures no se ejecutan.
Se ejecutan concurrentemente después de que la respuesta HTTP se haya enviado al usuario.
Ejemplo práctico: llamar a varias APIs externas a la vez
Piensa en un dashboard de un ecommerce que consume tres APIs: gestión de inventario, ventas y estado de envíos.Ejecución en serie (antes)
Ejecución concurrente (después)
Ejecutar varias agregaciones de base de datos a la vez
Configuración para pruebas
En el entorno de pruebas conviene usar el driversync, que ejecuta los closures uno tras otro.
Evitas el coste de arrancar procesos concurrentes y las pruebas se hacen más rápidas.
.env.testing.
Advertencias
Limitaciones de los closures
Limitaciones de los closures
Los closures se serializan y se pasan al proceso hijo.
No puedes capturar del exterior objetos no serializables (conexiones a base de datos, handles de archivo, recursos, etc.).
Crea dentro del closure los objetos que necesites.
Sobrecarga del driver process
Sobrecarga del driver process
El driver
process tiene el coste de arrancar procesos hijos, así que para operaciones muy cortas (unos pocos milisegundos) puede no ser más rápido.
Aporta beneficios cuando se paralelizan operaciones que tardan más de 100 ms, como solicitudes HTTP o agregaciones de base de datos.Limitaciones del driver fork
Limitaciones del driver fork
Como
fork hace fork del proceso PHP, no puede usarse durante una solicitud web (FPM o Apache).
Úsalo solo dentro de comandos Artisan o workers de cola.Manejo de excepciones
Manejo de excepciones
Si durante la ejecución concurrente se lanza una excepción,
run() la vuelve a lanzar.
Si quieres que el resto de operaciones continúen aunque una lance excepción, usa try/catch dentro del closure.Próximos pasos
Colas y jobs
Aprende a ejecutar procesos en segundo plano de forma asíncrona con colas y jobs