Workers de colas de Laravel en hosting compartido: siempre activos con cron

¿Usas las colas de Laravel para correo electrónico, importaciones u otras tareas en segundo plano? Entonces necesitas un worker de colas que procese los jobs. En un VPS se suele usar Supervisor para eso. Supervisor no está disponible en nuestro hosting compartido, pero tampoco lo necesitas. Con una tarea cron y flock mantienes un worker activo de forma continua, y vuelve a arrancar solo tras un reinicio o una incidencia.

Cómo funciona

Cron intenta arrancar el worker cada minuto. flock se encarga de que nunca se ejecute más de una instancia a la vez:

  • Si el worker ya se está ejecutando, el nuevo intento se detiene de inmediato.
  • Si el worker se ha detenido, por ejemplo tras un reinicio del servidor, un fallo o un despliegue, cron lo vuelve a arrancar en menos de un minuto.
  • Con --max-time, el worker se detiene de forma ordenada al cabo de un tiempo fijo. Así el consumo de memoria se mantiene bajo y siempre se ejecuta con tu código más reciente.

Con esto obtienes el mismo resultado que con Supervisor, sin software adicional.

¿Qué necesitas?

  • Un plan de hosting con SSH y tareas cron, como el plan Starter de hosting web o superior.
  • Un proyecto de Laravel que ya esté en funcionamiento. Consulta Instalar Laravel en hosting compartido.

Paso 1: elige la base de datos como cola

En el archivo .env, pon lo siguiente:

QUEUE_CONNECTION=database

Desde Laravel 11, la tabla jobs viene de serie en los proyectos nuevos. Si tienes un proyecto más antiguo sin esa tabla, créala por SSH:

php artisan make:queue-table
php artisan migrate

Consejo: en nuestros servidores, Redis está pensado como caché. Tras un reinicio pueden perderse los datos recientes. Por eso, elige la base de datos para los jobs que no se pueden perder, como el correo electrónico.

Paso 2: crea una carpeta para los archivos de bloqueo

Inicia sesión por SSH y ejecuta:

mkdir -p ~/locks

Paso 3: crea la tarea cron

En DirectAdmin, ve a Cron Jobs (consulta Configurar tareas cron en DirectAdmin). En minuto, hora, día, mes y día de la semana, escribe siempre * para que la tarea cron se ejecute cada minuto. Usa esto como comando:

/usr/bin/flock -n /home/GEBRUIKER/locks/worker1.lock /usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan queue:work --max-time=3600 --sleep=3 --tries=3 > /dev/null 2>&1

Sustituye GEBRUIKER por tu nombre de usuario de DirectAdmin y PAD-NAAR-PROJECT por la carpeta de tu proyecto de Laravel, por ejemplo domains/jouwdomein.nl/laravel.

Qué hace cada parte:

  • flock -n ...worker1.lock arranca el worker solo si todavía no hay ninguno en ejecución.
  • /usr/local/bin/php usa la versión de PHP que hayas elegido en DirectAdmin en Select PHP version.
  • Con --max-time=3600, el worker se detiene de forma ordenada al cabo de una hora y cron arranca uno nuevo de inmediato.
  • Con --sleep=3, si la cola está vacía, el worker comprueba cada 3 segundos si hay jobs nuevos.
  • Con --tries=3, un job que falla se intenta 3 veces como máximo y después pasa a la tabla failed_jobs.

Paso 4: el programador de tareas (si lo usas)

Si usas el programador de tareas de Laravel, añade una segunda tarea cron que se ejecute cada minuto:

/usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan schedule:run > /dev/null 2>&1

No arranques también el worker de colas desde el programador de tareas. La tarea cron del paso 3 ya se encarga de ello.

Más de un worker

Si necesitas más capacidad de procesamiento, añade una segunda tarea cron con su propio archivo de bloqueo:

/usr/bin/flock -n /home/GEBRUIKER/locks/worker2.lock /usr/local/bin/php /home/GEBRUIKER/PAD-NAAR-PROJECT/artisan queue:work --max-time=3600 --sleep=3 --tries=3 > /dev/null 2>&1

Cada worker necesita su propio archivo de bloqueo. Con el mismo bloqueo, solo se ejecuta uno cada vez. Si quieres un worker por cola, por ejemplo para el correo electrónico, añade --queue=mail.

Después de un despliegue

Los workers mantienen tu código en memoria. Después de subir código nuevo, ejecuta:

php artisan queue:restart

Los workers terminan su job actual y se detienen. En menos de un minuto, cron los vuelve a arrancar con el código nuevo.

Comprobar si el worker se está ejecutando

ps -u $USER -o pid,etime,cmd | grep "queue:work" | grep -v grep

Si ves una línea con artisan queue:work, el worker se está ejecutando. Los jobs fallidos se consultan con:

php artisan queue:failed

Conviene saber

  • Un worker suele usar entre 50 y 100 MB de memoria. Eso cuenta dentro de los límites de tu plan de hosting.
  • No arranques un worker con nohup o &. Un worker así no vuelve tras un reinicio y, sin flock, es fácil arrancar varios por error.
  • ¿Tienes pocos jobs? Entonces también puedes prescindir de un worker permanente: haz que cron ejecute cada minuto queue:work --stop-when-empty, también con flock. El worker procesa lo que esté pendiente y se detiene.
  • Si tienes un entorno de pruebas y uno de producción en planes de hosting separados, cada plan tiene sus propias tareas cron, workers y base de datos.

¿Necesitas ayuda?

¿No consigues resolverlo? Envíanos un mensaje a través del sistema de tickets y lo revisamos contigo.

¿Buscas hosting para tu aplicación Laravel? Consulta el hosting Laravel.