Utilizando las Colas o Queues y los Trabajos o Jobs para posponer Tareas en Laravel

Video thumbnail
Video thumbnail

Laravel, al permitir construir todo tipo de sistemas y podemos hacer todo tipo de debug, como ver las consultas SQL, desde sencillos hasta complejos, muchas veces se enfrenta a tareas que requieren un alto cómputo. Esta es una de las principales desventajas de las aplicaciones web frente a las aplicaciones de escritorio: las aplicaciones web, usualmente (al menos las tradicionales), cuentan con menos recursos de cómputo disponibles o son más limitadas.

Esto se nota al realizar operaciones relativamente sencillas, como enviar un correo o procesar una imagen. Si estas tareas se ejecutan en el hilo principal del servidor (el mismo que atiende las peticiones), el servidor puede tardar varios segundos en devolver una respuesta. Este tiempo adicional se debe al procesamiento de estas operaciones costosas. Además, si la operación excede la capacidad de cómputo o si muchas personas realizan estas operaciones simultáneamente, el servidor puede generar un error de agotamiento de tiempo (time exhaustion).

Solución: delegar operaciones mediante colas

Para resolver esto, debemos emplear un mecanismo que permita ejecutar estos procesos de manera eficiente. En lugar de realizarlas en el hilo principal, podemos delegar estas tareas a procesos secundarios, los cuales se encargan de ejecutarlas de manera consecutiva, una detrás de otra. Aquí es donde entran en juego las colas y los trabajos.

Trabajos y colas

Los trabajos son operaciones costosas en términos de cómputo: enviar correos, procesar imágenes, manejar archivos Excel, generar PDFs, etc. Estos trabajos se asignan a colas, que se encargan de procesarlos de forma eficiente. Podemos configurar varios procesos secundarios que trabajen sobre las colas para ejecutar estas tareas sin saturar el sistema.

Además, es posible:

  • Especificar prioridades en los trabajos para que algunos se ejecuten antes que otros.
  • Incrementar la capacidad de procesamiento de forma horizontal, añadiendo más trabajadores.
  • Reintentar trabajos que hayan fallado, mejorando la tolerancia a fallos del sistema.

Beneficios

Al emplear el sistema de colas y trabajadores, obtenemos:

  • Mejora en la capacidad de respuesta de la aplicación.
  • Ejecución de trabajos de manera asíncrona, sin afectar el hilo principal.
  • Procesamiento eficiente de operaciones costosas, incluso si hay múltiples tareas concurrentes.

En definitiva, las colas permiten que las aplicaciones web manejen trabajos pesados de manera confiable y escalable, evitando que el servidor se sature y manteniendo la experiencia del usuario fluida.

Así que aclarado la importancia de este sistema, vamos a conocer cómo implementarlo.

Controlador de cola

Primero, debemos de elegir un controlador de colar para emplear entre todos los existentes:

  • 'sync': El controlador 'sync' ejecuta los trabajos en cola justo después y en el mismo ciclo solicitud-respuesta. Es adecuado para entornos de desarrollo y pruebas, pero no para producción.
  • 'database: el controlador de 'base de datos' almacena los trabajos en cola en una tabla de base de datos en un proceso de trabajo de cola independiente.
  • 'redis': el controlador 'redis' utiliza Redis como almacén de cola.
  • 'beanstalkd': El controlador 'beanstalkd' utiliza el servicio de cola Beanstalkd, para procesar las colas.
  • 'sqs' (Amazon Simple Queue Service): el controlador 'sqs' se utiliza para la integración con Amazon SQS.
  • 'rabbitmq': el controlador 'rabbitmq'  permite utilizar RabbitMQ como controlador de cola.
  • 'null': el controlador nulo se utiliza para desactivar el sistema de colas por completo.

Configuración

Por defecto, está configurado el de la base de datos:

config\queue.php

'default' => env('QUEUE_CONNECTION', 'database')

Y para realizar las siguientes pruebas, puedes emplear el de database aunque, usualmente Redis es una excelente opción por ser una base de datos rápida y eficiente y que instalamos anteriormente y es la que usaremos:

config\queue.php

'default' => env('QUEUE_CONNECTION', 'redis')

Finalmente, iniciamos el proceso para ejecutar los trabajos mediante:

$ php artisan queue:work

Además, Laravel nos permite reintentar trabajos fallidos usando el comando:

$ php artisan queue:work --tries=3

Aquí indicamos el número de intentos que Laravel debe hacer para ejecutar nuevamente un trabajo en caso de que ocurra un error o excepción durante su ejecución.

Si un trabajo arroja una excepción, se considera trabajo fallido y Laravel puede gestionarlo según la configuración.

Y veremos por la consola:

INFO  Processing jobs from the [default] queue

Cada vez que se procesa un trabajo, verás por la terminal:

.................................................................... 3s DONE
  2026-07-12 09:44:31 App\Jobs\TestJob ............................................................................... RUNNING
  2026-07-12 09:44:34 App\Jobs\TestJob ............................................................................... 3s DONE
  2026-07-12 09:45:43 App\Jobs\TestJob ............................................................................... RUNNING

No importa si desde tus controladores o similares despachas trabajos y la cola NO está activa, Laravel las registras y cuando actives el proceso de la cola, las despacha; y esto es todo, ya con esto Laravel levanta un proceso para gestionar los trabajos, falta crear el trabajo que veremos en el siguiente apartado.

En esta entrada vamos a conocer el uso de las Colas y los Trabajos en Laravel (Queues y Jobs) para poder realizar trabajos en segundo plano.

La idea de esta API es que nosotros podemos aplazar tareas (dejarlas en segundo plano) que requieren un alto consumo de computo y todo esto es para mejorar la experiencia del usuario y evitar cuelgues en la aplicación; de tal manera que estas tareas de alto cómputo se ejecutarán en otro hilo o proceso en nuestro servidor y se irán resolviendo a medida que lleguen o dependiendo de la prioridad de las mismas.

Básicamente todo este proceso se lleva a cabo entre las tareas/trabajos/jobs (los procesos elevados de cómputo) y las colas (mecanismo para registrar los jobs).

De igual manera vamos a hablar un poco más en detalle de estos dos componentes fundamentales.

Los trabajos o jobs y las colas o queues

Los trabajos son la tarea pesada o que requieren mucho procesamiento que queremos aplazar; y pueden ser de cualquier tipo como envío masivo o simple de emails, procesar imágenes, vídeos etc; por lo tanto son estas tareas que nosotros vamos registrando como pendientes para que Laravel las vaya procesando uno a uno a medida que esta disponible; asi que lo siguiente que te puedes preguntan es, ¿Cómo se maneja esta organización?; es decir, quien es el que se encarga de manejar la prioridad entre tareas o trabajos (colas) y cómo mantenemos una organización de todo esto.

Los jobs

En Laravel, los jobs son una parte importante de la funcionalidad de la cola de trabajos del framework, es decir los jobs son usados para procesar los trabajos pesados almacenados mediante “colas”; estas tareas pesadas pueden ser cualquier cosa como envio de emails, procesar imágenes, vídeos entre otros; esto es ideal ya que, estas tareas no forman parte de la sesión principal del usuario y se evita consumir recursos de la sesión principal del usuario, aparte de que, se evita las famosas ventanas de “no responde” y en general, se tiene una mejor experiencia en el uso de la aplicación.ya que no afecta el rendimiento o la capacidad de respuesta de la aplicación principal.

Los jobs en Laravel pueden ser creados para realizar cualquier tarea que se necesite en el back-end sin que el usuario tenga que esperar a que se complete la tarea; es decir, como enviar un correo o exportar datos en un excel o un formato similar.

Lo estupendo de los jobs es que, se ejecutan de manera secuencial, suponte que creas un job para procesar correos, los correos se van enviando uno a uno sin necesidad de sobrecargar la página, cosa que no sucederia si el envio de correos se manejada desde la sesión principal del usuario y de repente, vengan 5 o más usuarios a enviar correos desde la aplicación, por lo tanto, en un mismo instante de tiempo, tendrias múltiples envios de correos y gastando los recursos que esto requiera.

En resumen, los jobs en Laravel son una parte esencial de la cola de trabajos del framework, y permiten que las tareas pesadas o no esenciales se realicen en segundo plano para mejorar el rendimiento y la capacidad de respuesta de la aplicación principal.

Las colas

Ya en este punto, hemos introducido el concepto de “colas” en el uso de los jobs, de igual manera, vamos a explicarlo rápidamente; las colas de trabajo corresponden a la operación que se quiere realizar, que como comentamos antes, corresponde a la operación “pesada” que se quiere realizar, es decir, en vez de enviar un correo desde un controlador, se almacena en una cola que luego es procesado mediante otro proceso.

Crea tus propias colas en Laravel para mantener el orden

La respuesta a lo comentado anteriormente es bastante simple, serían las colas como mecanismo que permiten registrar o añadir estos trabajos o jobs; podemos registrar o tener tantas colas como queramos y podemos especificar a Laravel mediante artisan que colas queremos que procesen primero; por ejemplo, veamos el siguiente ejemplo:

$ php artisan queue:work --queue=high,default

Mediante el comando anterior le estamos diciendo a Laravel que primero procese los trabajos de una cola llamada "hight" y luego lo de una cola llamada "default", que por cierto, es la cola que tenemos definida por defecto.

Conexiones para la estructura para mantener las colas

Las conexiones son la manera predeterminada que tenemos para indicar cómo se va a llevar a cabo todo el proceso de las colas (ya que recuerda que la cola absorbe a la tarea, por lo tanto, en este punto, una vez registrada la tarea o job en una cola, en nuestro cola la tarea ya no pinta nada); pero para poder emplear toda esta estructura debemos indicar la conexión y con ella debemos indicar:

  • El controlador o driver
  • Valores predeterminados o de configuración

Por lo tanto, mediante la conexiones nosotros podemos especificar el driver que vamos a emplear que puede ser cualquier como la base de datos u otros servicios; por ejemplo:

Base de datos:

  1. Amazon SQS: aws/aws-sdk-php ~3.0
  2. Beanstalkd: pda/pheanstalk ~4.0
  3. Redis: predis/predis ~1.0 or phpredis PHP extension

Y algunos parámetros extra para la configuración.

Configurar el Driver o conector de las colas para la base de datos

Ahora vamos a abrir el archivo de config/queue.php y el .env, en los cuales vamos a buscar una configuración llamada QUEUE_CONNECTION

Que por defecto se llama QUEUE_CONNECTION y tiene la configuración de sync, que si lo analizas un poco verás que tenemos varios tipos de conexiones que podemos emplear, entre ella la llamada database que es la que vamos a emplear, por lo tanto configúralo al menos en el archivo de .env; en mi caso lo voy a dejar así en el .env:

QUEUE_CONNECTION=database
Y en el config/queue.php quede:
    'default' => env('QUEUE_CONNECTION''database'),

Crear la tabla de jobs en nuestra base de datos

Ahora bien lo siguiente que de puedes preguntar sería, ¿cómo nosotros podemos configurar la tabla en nuestra base de datos?; siguiente la documentación oficial:

$ php artisan queue:table php artisan migrate

Ya tenemos un comando de artisan que nos ayuda en todo este proceso, que sería el que nos permite generar la migración para crear la tabla; y con esto estamos listos.

Creando nuestro primer Job en Laravel

Ahora vamos a crear nuestro primer Job que vamos a configurar con la cola de default; para eso, vamos a crear uno mediante nuestro artisan:

$ php artisan make:job ProcessImageSmall

Y con esto tenemos un archivo generado en App\Jobs

El cual consta de dos bloques principales:

  1. __construct
  2. handle

La función constructora para inicializar los datos básicos que vamos a emplear y la función de handle para hacer el proceso pesado; así de simple, por lo tanto en la función de handle podemos enviar los emails, procesar videos o imágenes, para nuestro ejemplo vamos a suponer que tenemos una imagen que estamos recibiendo por parámetros:

  protected $image;
 
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(PostImage $image)
    {
        $this->image = $image;
    }

Esta imagen es básicamente una instancia de un modelo que luce de la siguiente manera:

class PostImage extends Model
{
    protected $fillable = ['post_id', 'image'];
 
    public function post(){
        return $this->belongsTo(Post::class);
    }
 
    public function getImageUrl(){
        return URL::asset('images/'.$this->image);
        //return Storage::url($this->image);
    }
}

Y ahora, vamos a hacer un proceso pesado como escalar una imagen; para esto, vamos a emplear el siguiente paquete que podemos instalar mediante composer:

$ composer require intervention/image

El código que vamos a emplear, básicamente se auto explica solo:

<?php
 
namespace App\Jobs;
 
use App\PostImage;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
 
use Intervention\Image\ImageManagerStatic;
 
class ProcessImageSmall implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 
    protected $image;
 
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(PostImage $image)
    {
        $this->image = $image;
    }
 
    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $image = $this->image;
 
        $fullPath = public_path('images' . DIRECTORY_SEPARATOR . $image->image);
        $fullPathSmall = public_path('images' . DIRECTORY_SEPARATOR . 'small' . DIRECTORY_SEPARATOR . $image->image);
 
        $img = ImageManagerStatic::make($fullPath)->resize(300,200);
        $img->save($fullPathSmall);
    }
}

En el cual simplemente creamos una instancia de nuestro paquete, que instalamos anteriormente, especificamos la ubicación de la imagen y mediante la función de resize escalamos la imagen a las dimenciones especificadas; luego, guardamos la nueva imagen y con esto estamos listos.

Despachar un trabajo

Lo siguiente que tenemos que especificar, seria en donde nosotros vamos a llamar a este trabajo, que puede ser en cualquier parte de nuestra aplicación como cuando nosotros cargamos una imagen, etc; supongamos que tenemos un método para cargar una imagen en Laravel por ejemplo:

  public function image(Request $request, Post $post)
    {
        $request->validate([
            'image' => 'required|mimes:jpeg,bmp,png|max:10240', //10Mb
        ]);
 
        $filename = time() . "." . $request->image->extension();
 
        $request->image->move(public_path('images'), $filename);
 
        //$path = $request->image->store('public/images');
 
        $image = PostImage::create(['image' => /*$path*/ $filename, 'post_id' => $post->id]);
 
        ProcessImageSmall::dispatch($image);
 
        return back()->with('status', 'Imagen cargada con exito');
 
    }

Desde aquí; si te fijas bien en el código, verás que definimos una instancia de nuestra cola con el método de dispatch para despachar el trabajo ProcessImageSmall::dispatch($image)

Levantar el demonio para procesar las colas

Ahora si revisamos la tabla anterior, veremos que se registró un trabajo, pero el mismo no ha sido despachado, para despachar el mismo, tenemos que activar el demonio que se encarga de hacer esta labor, levantar el proceso que se encarga de hacer los trabajos pendientes en la tabla jobs:

$ php artisan queue:work

Y con esto veremos que tenemos todo listo y el trabajo ya fue despachado:

Despachar trabajo

Con esto, aprendimos a emplear los trabajos y las colas en Laravel; recuerda que esto es uno de los muchísimos temas que tratamos en profundidad en nuestro curso de Laravel que puedes tomar en esta plataforma en la sección de cursos.

Problemas del procesamiento en el hilo principal

Cuando realizamos operaciones costosas en el hilo principal, el servidor puede tardar varios segundos en responder. Esto ocurre, por ejemplo, al:

  • Procesar imágenes.
  • Generar PDFs.
  • Leer archivos Excel.
  • Enviar correos masivos.

Si muchos usuarios ejecutan estas operaciones simultáneamente, el servidor puede saturarse, mostrar errores 500 o superar los tiempos máximos de ejecución. Esto afecta la experiencia del usuario y la estabilidad del sistema.

Ejemplo práctico: 20 cajas

  • Imagina que debes transportar 20 cajas grandes:
  • Si te las dan todas al mismo tiempo, será imposible manejarlas sin que se caigan.
  • Si te las dan una por una, podrás colocarlas correctamente en su destino.

Lo mismo ocurre con el servidor: procesar tareas costosas una a una mediante colas y trabajos evita saturación y errores de memoria.

Trabajos (Jobs) y Colas (Queues)

Trabajos (Jobs) 

Los trabajos son tareas costosas o complejas que requieren alto cómputo, como:

  • Enviar correos.
  • Procesar imágenes.
  • Generar PDFs.
  • Leer o manipular archivos Excel.

Cada trabajo es una clase que encapsula una operación específica, con sus parámetros y lógica interna. Por ejemplo, podrías tener un trabajo que reciba un usuario y envíe un correo de bienvenida.

Colas (Queues)

Las colas son los procesos que gestionan los trabajos. Estas se ejecutan en hilos secundarios, de manera asíncrona y secuencial, evitando bloquear el hilo principal.

  • Podemos configurar varios procesos secundarios para procesar trabajos en paralelo si el servidor lo permite.
  • Los trabajos se procesan uno a uno, evitando saturación y mejorando la tolerancia a fallos del sistema.
  • Si un trabajo falla, se puede reintentar automáticamente.

Trabajos vs Procesamiento en el hilo principal

Procesar trabajos en el hilo principal implica que la aplicación debe manejar todo al mismo tiempo. Esto provoca:

  • Respuestas lentas al usuario.
  • Posibles errores 500 si el servidor se satura.
  • Mala experiencia de usuario.

Con colas y trabajos, las tareas se ejecutan de forma secuencial o controlada:

  • Los trabajos se agregan a la cola y se procesan uno a uno.
  • El hilo principal sigue atendiendo otras solicitudes sin bloquearse.
  • La experiencia del usuario mejora y la aplicación es más estable.

Ejemplo práctico: simulando varios clientes

Supongamos que tres clientes envían solicitudes simultáneamente:

  • Si procesamos las tareas en el hilo principal, el servidor puede saturarse o las operaciones tardar mucho tiempo.
  • Con las colas, cada trabajo se encola y se procesa uno a uno, evitando saturación.
  • Esto simula un flujo controlado, como recibir cajas de una en una en lugar de todas al mismo tiempo.

Drivers de colas

Laravel ofrece varios drivers para gestionar las colas:

  • sync: ejecuta el trabajo de manera síncrona en el hilo principal. Útil solo en desarrollo o pruebas.
  • database: almacena la cola en la base de datos. Simple y funcional para pruebas.
  • redis: muy rápido, recomendado para producción. Funciona con bases de datos clave-valor.
  • null: deshabilita las colas.

El driver que uses no afecta la implementación; solo cambia el mecanismo de almacenamiento y procesamiento de las tareas.

Creación de un Job en Laravel

Crear el trabajo con Artisan:

$ php artisan make:job TestJob

En la clase generada:

Definir atributos y constructor si el trabajo requiere parámetros.

Implementar el método handle() con la lógica de la operación.

Ejemplo sencillo: un trabajo que duerme 3 segundos para simular un proceso costoso:

public function handle()
{
   Log::info('Before sleep');
   sleep(3);
   Log::info('After sleep');
}

Despachar el trabajo desde un controlador o ruta:

TestJob::dispatch($parametro);

Iniciar el worker de la cola:

$ php artisan queue:work

Los trabajos se ejecutarán en el hilo secundario, sin bloquear el flujo principal de la aplicación.

Beneficios finales

  • Mejora la capacidad de respuesta de la aplicación.
  • Incrementa la tolerancia a fallos: trabajos costosos no se pierden si el servidor se bloquea.
  • Permite procesamiento asíncrono de tareas complejas.
  • Es escalable: puedes agregar más procesos para procesar múltiples trabajos en paralelo.

Otro desarrollo interesante, ya que hemos avanzado mucho con desarrollos en Laravel, es conocer como tener una app multilingüe.

En esta entrada vamos a conocer el uso de las Colas y los Trabajos en Laravel (Queues y Jobs) para poder realizar trabajos en segundo plano.

Acepto recibir anuncios de interes sobre este Blog.

Andrés Cruz

EN In english