JOBS Y QUEUES EN LARAVEL: CÓMO PROCESAR TAREAS EN SEGUNDO PLANO
En cualquier aplicación Laravel que crezca, llega un momento en el que ciertas operaciones no pueden bloquear la respuesta HTTP del usuario. Enviar emails masivos, procesar imágenes, sincronizar con APIs externas, generar reportes o indexar datos son tareas que deben ejecutarse en segundo plano. Ahí es donde entran en juego los Jobs y las Queues de Laravel siendo una de las características más poderosas y elegantes del framework.¿Qué son las Queues?
Las Queues, o colas, permiten mover tareas pesadas fuera del ciclo de vida de la petición HTTP. En lugar de que el usuario espere 5-10 segundos mientras se envía un email o se procesa un vídeo, Laravel devuelve la respuesta inmediatamente y ejecuta la tarea de forma asíncrona. Su beneficio principales son- Mejora drástica del tiempo de respuesta.
- Mejor experiencia de usuario.
- Posibilidad de reintentar tareas fallidas automáticamente.
- Escalabilidad horizontal: puedes tener múltiples workers procesando colas.
- Separación clara entre lógica síncrona y asíncrona.
¿Qué es un Job en Laravel?
Un Job es una clase que representa una tarea específica que se puede poner en cola. Laravel genera estas clases con un comando artisan muy sencillo:php artisan make:job SendWelcomeEmail
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class SendWelcomeEmail implements ShouldQueue
{
use Queueable;
public $user;
public function __construct($user)
{
$this->user = $user;
}
public function handle()
{
// Lógica del job (enviar email, etc.)
Mail::to($this->user)->send(new WelcomeMail($this->user));
}
}
// Despacho inmediato
SendWelcomeEmail::dispatch($user);
// Despacho retardado (ej: después de 10 minutos)
SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(10));
// Despacho después de que se envíe la respuesta HTTP (Laravel 11+)
SendWelcomeEmail::dispatch($user)->afterResponse();
dispatch(new SendWelcomeEmail($user));
Configuración de las Queues
Los jobs y las colas se configuran en el archivo "config/queue.php". Los drivers más usados son:- database → Ideal para empezar (fácil de configurar y depurar).
- redis → El más recomendado en producción por su velocidad y características (soporta Horizon).
- sqs (Amazon SQS) → Perfecto si estás en AWS.
- beanstalkd, sync (para testing) y null.
php artisan queue:table
php artisan migrate
Ejecutar los Workers
El comando principal para procesar las colas es:php artisan queue:work
- "--queue=high, default"→ procesar varias colas por prioridad.
- "--tries=3" → número máximo de intentos.
- "--timeout=60" → tiempo máximo por job.
- "--backoff=3" → segundos de espera antes de reintentar.
Características avanzadas
- Job Chaining (encadenamiento de jobs):
ProcessPodcast::withChain([ OptimizePodcast::class, ReleasePodcast::class, ])->dispatch($podcast); - Job Batching → Ejecutar un grupo de jobs y recibir notificación cuando todos terminen.
- Rate Limiting en jobs (disponible desde Laravel 8+).
- Middleware de Jobs → Puedes crear middlewares personalizados para logging, throttling, etc.
- Failed Jobs → Laravel guarda automáticamente los jobs que fallan en la tabla failed_jobs. Se puede reintentar con:
php artisan queue:retry all - Horizon (para Redis) → Un dashboard hermoso para monitorear colas en tiempo real, métricas, balanceo, etc.
Mejores prácticas
- Usar Redis en producción siempre que sea posible es más rápido y con mejor soporte para prioridades.
- Hacer que loa jobs que puedan ejecutarse varias veces sin efectos secundarios.
- Mantener los jobs lo más ligeros posible. La lógica pesada debe ir en Actions o Services.
- Para tareas muy pequeñas que solo necesitan ejecutarse después de la respuesta, considerar defer() (nuevo en Laravel 11).
- Separar los workers del servidor web cuando la aplicación crezca.
- Monitorizae siempre los failed jobs y configurar alertas.
Ejemplo real
Ejemplo con el código de procesamiento de imágenes. Primero crear el job con el comando Artisan::php artisan make:job ProcessUploadedImage
//app/Jobs/ProcessUploadedImage.php
namespace App\Jobs;// ← Este es el namespace estándar
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class ProcessUploadedImage implements ShouldQueue
{
use Queueable;
public function __construct(public $imagePath) {}
public function handle(): void// ← Recomendado agregar : void en versiones modernas
{
// Redimensionar, optimizar, subir a S3, etc.
ImageOptimizer::process($this->imagePath);
}
}
ProcessUploadedImage::dispatch($path)
->onQueue('images') // cola específica
->delay(now()->addSeconds(5));