Ábrela cuando un job no se procesa, un worker no recoge el código nuevo o tienes que revisar los logs en el servidor. Si no sabes por dónde empezar, ve a los escenarios del final: cada uno da el orden en que mirar.
1. Colas: inspeccionar y probar
Abre la consola interactiva de Laravel para consultar la configuración y las colas.
php artisan tinker
Lista las conexiones de cola registradas (dentro de tinker).
>>> array_keys(config('queue.connections'));
Muestra los jobs pendientes de la cola con el driver database (dentro de tinker).
>>> DB::table('jobs')->where('queue','emails')->get();
Encola un job de prueba para comprobar que el worker lo recoge (dentro de tinker).
>>> dispatch(new \App\Jobs\ExampleJob);
Cuenta los jobs que aún no se han intentado, consultando directamente la tabla jobs.
SELECT * FROM jobs WHERE queue = 'emails' AND attempts = 0;
Mide cuántos jobs esperan en la cola si usas el driver Redis.
redis-cli
> LLEN queues:emails
2. Workers con Supervisor
Supervisor mantiene vivos los procesos queue:work. Tras tocar la configuración, el ciclo es reread, update y restart.
Abre la definición del programa de Supervisor para editarla.
sudo nano /etc/supervisor/conf.d/app-workers.conf
Recarga la configuración y aplica los cambios a los procesos.
sudo supervisorctl reread
sudo supervisorctl update
Comprueba el estado de todos los workers del programa.
sudo supervisorctl status app-workers:*
Reinicia todos los workers del programa, por ejemplo tras un despliegue.
sudo supervisorctl restart app-workers:*
Tras cada despliegue, reinicia los workers: ejecutan el código que cargaron en memoria al arrancar, así que sin reinicio siguen con la versión anterior.
3. Seguir logs en producción
Sigue en tiempo real el log de los workers.
tail -f /var/www/app/current/storage/logs/worker.log
Sigue en tiempo real el log de la aplicación.
tail -f /var/www/app/current/storage/logs/laravel.log
Sigue un log con less para poder buscar con /patrón; Ctrl-C para el seguimiento.
less +F /var/www/app/current/storage/logs/worker.log
Muestra las últimas 100 líneas de un log.
tail -n 100 /var/www/app/current/storage/logs/worker.log
Sigue varios logs a la vez en la misma pantalla.
multitail \
/var/www/app/current/storage/logs/worker.log \
/var/www/app/current/storage/logs/laravel.log
Navega por todos los logs con resaltado y filtros.
lnav /var/www/app/current/storage/logs/*.log
4. Filtrar logs
Sigue el log mostrando solo las líneas de un job concreto; --line-buffered hace que grep no retenga la salida.
tail -f /var/www/app/current/storage/logs/worker.log \
| grep --line-buffered 'ExampleJob'
Sigue solo las líneas de un job en estado RUNNING o DONE.
tail -f /var/www/app/current/storage/logs/worker.log \
| grep --line-buffered -E 'ExampleJob.*(RUNNING|DONE)'
Busca errores en todos los logs, con número de línea.
grep -R "ERROR" -n /var/www/app/current/storage/logs
Cuenta cuántas veces aparece un job en el log.
grep -c "ExampleJob" /var/www/app/current/storage/logs/worker.log
Filtra las líneas de un día concreto.
grep "2026-10-06" /var/www/app/current/storage/logs/worker.log
5. Tamaño, limpieza y rotación de logs
Mide cuánto ocupa la carpeta de logs.
du -sh /var/www/app/current/storage/logs
Lista los logs ordenados por tamaño.
ls -lh /var/www/app/current/storage/logs | sort -k5 -h
Vacía un log sin borrar el fichero, conservando su inodo y sus permisos.
truncate -s 0 /var/www/app/current/storage/logs/worker.log
Revisa cómo rota logrotate los logs de la aplicación.
cat /etc/logrotate.d/laravel
6. Permisos de storage y bootstrap/cache
El fallo más común tras un despliegue: el servidor web no puede escribir en storage o bootstrap/cache.
Comprueba el propietario y los permisos de storage y de su carpeta de logs.
ls -ld /var/www/app/current/storage
ls -ld /var/www/app/current/storage/logs
Asigna storage y bootstrap/cache al usuario del servidor web.
sudo chown -R www-data:www-data \
/var/www/app/current/storage/ \
/var/www/app/current/bootstrap/cache
Da permisos 775 a todos los directorios de storage y bootstrap/cache.
find /var/www/app/current/storage/ /var/www/app/current/bootstrap/cache -type d -exec chmod 775 {} \;
Da permisos 664 a todos los ficheros de storage y bootstrap/cache.
find /var/www/app/current/storage/ /var/www/app/current/bootstrap/cache -type f -exec chmod 664 {} \;
7. Caché de configuración
Regenera la caché de configuración tras cambiar .env o config/*.
php artisan config:clear
php artisan config:cache
Cachea las rutas para que no se resuelvan en cada petición.
php artisan route:cache
Precompila las vistas Blade.
php artisan view:cache
Tras
config:cache, Laravel deja de leer.enven tiempo de ejecución y usa la caché. Si cambias una variable de entorno y no ves el efecto, regenera la caché.
8. Inventariar jobs y colas en el código
Antes de tocar Supervisor conviene saber qué colas existen y cómo están configuradas. Estos comandos se lanzan desde la raíz del proyecto.
Lista todos los ficheros de job.
find app -type f -path '*/Jobs/*.php'
Muestra la cola que declara cada job.
grep -R "public \$queue" -n app/Jobs
Muestra el timeout que declara cada job.
grep -R "public \$timeout" -n app/Jobs
Lista los jobs que se encolan, es decir, los que implementan ShouldQueue.
grep -R "implements ShouldQueue" -n app/Jobs
Encuentra dónde se asigna la cola en el momento de despachar.
grep -R "onQueue" -n app
9. Escenario: los jobs se quedan en la cola
situaciónLos jobs se encolan pero nadie los procesa: la cola crece y los correos no salen.
qué hay que entender
Un worker queue:work es un proceso largo: arranca, carga la aplicación en memoria y escucha una conexión y unas colas concretas. Supervisor lo mantiene vivo. Si el worker está caído, colgado o escucha otra cola u otra conexión, los jobs esperan sin que nada falle.
Como el worker no relee el código, tras un despliegue sigue con la versión anterior. queue:restart le pide que termine el job en curso y salga, y Supervisor lo vuelve a levantar con el código nuevo.
pasos, en orden
-
Mira si los workers están en marcha:
RUNNINGestá bien;FATAL,BACKOFFoSTOPPED, no.sudo supervisorctl status app-workers:* -
Revisa qué conexión y qué colas escucha el worker, en la línea
commanddel programa.grep '^command' /etc/supervisor/conf.d/app-workers.conf -
Comprueba a qué conexión envía los jobs la aplicación: debe coincidir con la del worker.
grep '^QUEUE_CONNECTION' /var/www/app/current/.env -
Procesa un solo job en primer plano, con el usuario del servidor web, para ver el error en directo.
sudo -u www-data php /var/www/app/current/artisan queue:work --queue=emails --once -
Si los workers están caídos o colgados, reinícialos desde Supervisor.
sudo supervisorctl restart app-workers:* -
Tras cada despliegue, pide a los workers que se reinicien para que carguen el código nuevo.
php /var/www/app/current/artisan queue:restart
cómo sé que está resuelto
supervisorctl status muestra todos los procesos en RUNNING y la cola baja: con Redis, LLEN queues:emails tiende a 0. Un job de prueba encolado desde tinker aparece en el log de los workers.
si no funciona
Si un worker pasa a FATAL al poco de arrancar, lee su salida con sudo supervisorctl tail -f seguido del nombre del proceso que da status. Si queue:restart no tiene efecto, revisa el driver de caché: la señal se guarda en la caché, y con array no llega a los workers. Y si cambiaste .env con la configuración cacheada, regenera config:cache.
en una entrevista«Los jobs de una cola no se procesan. ¿Qué miras?»
- Hay workers vivos:
supervisorctl status, porque sin proceso no hay nada más que mirar. - Escuchan lo que toca: comparo la conexión y la cola del worker con las que usa la aplicación.
- Están procesando: un
queue:work --onceen primer plano me enseña el error sin intermediarios. - Llevan el código nuevo: si viene de un despliegue,
queue:restartforma parte del propio despliegue.
La trampa que conviene nombrar: un worker sin reiniciar tras desplegar sigue ejecutando el código viejo, y el fallo parece del código nuevo.
10. Escenario: los jobs fallan una y otra vez
situaciónLos jobs se recogen pero acaban en «failed», o se ejecutan dos veces.
qué hay que entender
Un job se intenta tantas veces como diga --tries o el propio job. Al agotar los intentos pasa a la tabla failed_jobs, con la excepción completa. Ahí está el motivo, no en la cola.
Hay dos tiempos que se confunden. El --timeout del worker mata un job que tarda demasiado. El retry_after de la conexión dice cuántos segundos espera la cola antes de dar por perdido un job en curso y entregarlo otra vez. Si retry_after es menor que --timeout, un job lento se ejecuta dos veces.
pasos, en orden
-
Lista los jobs fallidos con su cola, su clase y cuándo fallaron.
php /var/www/app/current/artisan queue:failed -
Lee la excepción de los últimos fallos, directamente en la tabla.
SELECT id, queue, failed_at, LEFT(exception, 300) AS error FROM failed_jobs ORDER BY failed_at DESC LIMIT 5; -
Mira el
retry_afterde cada conexión de cola.grep -n "retry_after" /var/www/app/current/config/queue.php -
Compáralo con el
--timeoutdel worker: el timeout tiene que ser varios segundos menor.grep -o -- '--timeout=[0-9]*' /etc/supervisor/conf.d/app-workers.conf -
Con la causa corregida, desplegada y los workers reiniciados, reintenta los jobs fallidos.
php /var/www/app/current/artisan queue:retry all
cómo sé que está resuelto
queue:failed queda vacío o deja de crecer, y en el log de los workers los jobs reintentados aparecen como DONE.
si no funciona
Si el fallo solo ocurre a veces, busca la clase en el log con contexto: grep -A 20 'ExampleJob' sobre laravel.log. Para reintentar solo uno, pasa su ID a queue:retry. Un job que no tiene sentido repetir se descarta con queue:forget y su ID. Si se ejecuta dos veces aunque no falle, vuelve al paso 4.
en una entrevista«Un job falla una y otra vez. ¿Cómo lo investigas?»
- El motivo está en
failed_jobs: leo la excepción antes de tocar nada. - Clasifico el fallo: error del código, dato que falta o dependencia externa que no responde.
- Reviso los tiempos:
--timeoutdel worker por debajo deretry_afterde la conexión. - Corrijo, despliego y reinicio los workers antes de reintentar.
- Reintento con cuidado: solo si el job es idempotente, es decir, si repetirlo no duplica efectos.
Lo que no haría: un queue:retry all antes de corregir la causa, que vuelve a llenar la tabla de fallos.
11. Escenario: error 500 justo después de desplegar
situaciónTras un despliegue, la aplicación devuelve «500 Server Error» en todas las páginas.
qué hay que entender
En producción, con APP_DEBUG=false, Laravel enseña un 500 genérico y escribe el error real en storage/logs/laravel.log. Ese fichero es lo primero, porque dice la causa exacta.
Tras un despliegue, las causas típicas son cuatro. Una caché de configuración o de rutas con datos de la versión anterior. Permisos que impiden escribir en storage o bootstrap/cache. Migraciones sin aplicar. O una variable de .env que falta.
pasos, en orden
-
Lee las últimas líneas del log de la aplicación.
tail -n 50 /var/www/app/current/storage/logs/laravel.log -
Comprueba que
storageybootstrap/cachepertenecen al usuario del servidor web.ls -ld /var/www/app/current/storage /var/www/app/current/bootstrap/cache -
Si no es así, devuélveselos.
sudo chown -R www-data:www-data \ /var/www/app/current/storage \ /var/www/app/current/bootstrap/cache -
Borra las cachés de configuración, rutas y vistas con ese mismo usuario, para no dejar ficheros de root.
sudo -u www-data php /var/www/app/current/artisan optimize:clear -
Mira si quedan migraciones sin aplicar.
php /var/www/app/current/artisan migrate:status -
Aplícalas;
--forcees obligatorio en producción, donde Laravel pide confirmación.php /var/www/app/current/artisan migrate --force
cómo sé que está resuelto
La aplicación responde, por ejemplo curl -I a la portada devuelve 200, y laravel.log deja de crecer con errores. Después, regenera config:cache y route:cache con el usuario del servidor web.
si no funciona
Si laravel.log no tiene nada, Laravel no llegó a arrancar o no puede escribir: mira el log de errores del servidor web, como /var/log/nginx/error.log, y el de PHP-FPM. Si el error nombra una variable o una clave vacía, compara .env con el de la versión anterior. Si nada lo explica pronto, vuelve a la versión anterior y sigue sin la web caída.
en una entrevista«Acabas de desplegar y la web da un 500. ¿Qué haces?»
- El log primero:
laravel.logdice la causa; sin él estoy adivinando. - Qué ha cambiado: código,
.env, dependencias o esquema de base de datos. - Causas típicas, en orden: caché vieja, permisos de
storageybootstrap/cache, migraciones y entorno. - Artisan con el usuario correcto: si lo lanzo como root, las cachés nuevas quedan de root y el 500 vuelve.
- Si tarda, vuelvo atrás: una versión anterior que funciona vale más que diagnosticar en caliente.
12. Escenario: el log crece sin parar y llena el disco
situaciónEl fichero laravel.log ocupa gigas y el servidor se queda sin disco.
qué hay que entender
Con el canal single, Laravel escribe siempre en el mismo laravel.log y nunca lo recorta. El canal daily crea un fichero por día y borra los más antiguos que los días configurados. La otra opción es logrotate, pero no las dos sobre el mismo fichero.
El nivel también cuenta: con LOG_LEVEL=debug en producción se escribe todo. Y un worker es un proceso largo que mantiene abierto el log, así que borrarlo no libera el espacio hasta reiniciarlo; vaciarlo, sí.
pasos, en orden
-
Mira qué logs ocupan más, ordenados por tamaño.
ls -lhS /var/www/app/current/storage/logs | head -n 10 -
Comprueba el canal y el nivel de log configurados.
grep -E '^LOG_(CHANNEL|LEVEL)' /var/www/app/current/.env -
Libera espacio ya vaciando el log en vez de borrarlo, para que los procesos que lo tienen abierto lo suelten.
truncate -s 0 /var/www/app/current/storage/logs/laravel.log -
Pon
LOG_CHANNEL=dailyyLOG_LEVEL=warningen.env, y regenera la caché para que se aplique.sudo -u www-data php /var/www/app/current/artisan config:cache -
Si prefieres
logrotate, simula su configuración sin rotar nada para ver qué haría.sudo logrotate -d /etc/logrotate.d/laravel
cómo sé que está resuelto
df -h vuelve a dejar margen, aparece un laravel- con la fecha del día en storage/logs y el volumen de escritura baja al quitar el nivel debug.
si no funciona
Si el que crece es worker.log y lo escribe Supervisor, la rotación se configura en el programa con stdout_logfile_maxbytes y stdout_logfile_backups. Si el espacio no aparece, revisa los releases antiguos y su storage. Para el resto del diagnóstico, sigue el escenario «el disco está lleno» de Linux & Sysadmin.
en una entrevista«El log de Laravel ha llenado el disco. ¿Cómo lo resuelves y cómo evitas que vuelva?»
- Contener: vacío el log con
truncate, no lo borro, porque los procesos lo tienen abierto. - Causa: un único fichero sin rotar, un nivel
debugen producción o un error que se repite en bucle. - Rotación: canal
dailycon retención, ologrotate, pero no los dos sobre el mismo fichero. - Prevenir: nivel
warningo superior en producción y una alarma de disco antes del 100 %.
La trampa que conviene nombrar: si el log crece por un error repetido, rotar solo esconde el problema.
13. Relacionado
Ningún bloque coincide con el filtro.