The symptom
Mails or syncs never happen, failed_jobs stays empty, and supervisorctl status says the worker is running. The jobs are there, on a queue nobody reads.
Check it yourself
Where does the application write? QUEUE_CONNECTION is the default connection; packages and features may have their own *_QUEUE_CONNECTION and *_QUEUE_NAME.
grep -E 'QUEUE' .env
ps aux | grep -E 'queue:(work|listen)'
Then compare: a worker started as queue:work redis --queue=messaging reads only the messaging queue on Redis. Jobs written to default, or to the database connection, are never picked up. Count what is waiting:
# database connection
SELECT queue, COUNT(*) FROM jobs GROUP BY queue;
# redis connection (add your Redis key prefix if you set one)
redis-cli LLEN queues:default
How it happens
On a server we run, a site wrote its jobs to the database connection on the default queue, while its worker listened only to messaging. About 42,000 jobs waited for five months.
Before you start a worker on a queue that has been waiting for months, look at what the jobs are. Those were syncs that no longer mattered: they were deleted, not run late.
The fix
Start the worker on the connection the site writes to, with every queue it uses, in order of priority:
php8.4 artisan queue:work redis --queue=messaging,default --timeout=150
- Keep the connection's
retry_afterlonger than the worker's--timeout(hereREDIS_QUEUE_RETRY_AFTER=180), or a slow job is started twice. - After changing
.env, restart the workers:php artisan queue:restart. - Sites on Horizon configure this in
config/horizon.phpinstead.
How Hostio finds it
The scan reads only the queue keys of the site's .env and the queue:work and queue:listen workers that run for it. Every connection and queue the site writes to must have a worker that reads it; if not, it raises queue_mismatch: a danger insight when the site has workers but none listens there, an info insight when it has no worker at all. Sites on Horizon are not judged.
On Pro, the site's Queue tab has New queue worker, which builds the queue:work command from the connection and queue you pick. A related check, queue_retry_after_short, warns when retry_after is not longer than the timeout.