Laravel queue job does not work in background
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Laravel Queue Job Does Not Work in the Background: A Senior Developer's Guide
The Frustration of Synchronous Operations
Hello there! As a developer, one of the most common points of friction when building modern applications is managing asynchronous tasks. You want to dispatch an email after a user creation, but instead of letting the process happen silently in the background while the user waits for the redirect, you end up blocking the request thread and forcing the user to wait.
You've encountered this exact scenario: dispatching a job using dispatch(new WelcomeEmail($user)) followed by manually running Artisan::call('queue:work'), yet nothing seems to happen in the background as expected. This usually points not to a bug in your code, but rather a misunderstanding of how Laravel queues are configured and executed within your specific environment.
Let's dive deep into why this happens and how we can ensure your jobs run reliably in the background.
Diagnosis: Why Your Queue Isn't Working
The sequence you provided is conceptually correct for dispatching a job, but it misses the crucial element of persistent execution.
$this->dispatch(new WelcomeEmail($user));
Artisan::call('queue:work');
When you execute Artisan::call('queue:work'), you are telling Laravel to run the queue worker once, process any jobs currently waiting in the queue, and then exit. If no jobs were waiting when you ran this command (or if the system that runs the worker is not set up as a persistent service), the operation completes instantly, giving you the false impression that the job didn't start or run at all.
The core issue usually lies in one of three areas: Environment setup, Queue Driver configuration, or Worker management.
1. Environment and Configuration Check
For any queue system to function effectively, the environment must be correctly configured. Since you are using the database driver, Laravel relies entirely on Eloquent models and database tables to store jobs.
- Database Setup: Ensure your queue table (usually
jobs) exists in your database. - Configuration: Verify that your
.envfile correctly points to a valid database connection. If the connection fails during the job processing, the worker might silently fail or throw an error you miss if it's not properly logged.
As we build robust systems on top of Laravel, understanding these underlying mechanics is key. For instance, effective data handling and service architecture are central to scalable applications, much like how powerful frameworks guide us in structuring our code—a principle that aligns with the philosophy behind platforms like laravelcompany.com.
2. Persistent Worker Management (The Real Fix)
The most common reason jobs don't run continuously is that the queue worker process is not running perpetually on your server. Running queue:work manually only processes what’s currently waiting; it doesn't keep listening for new jobs.
To run a job persistently in the background, you must use a dedicated process manager. This ensures that if the web request finishes, the worker process remains active and will continue polling the queue for new tasks.
The Solution: Using Supervisor or Systemd
You should never rely on manually executing Artisan commands on a server for long-running processes. Instead, you deploy your queue worker as a persistent service using tools like Supervisor (on Linux systems) or Systemd.
A typical Supervisor configuration file would look something like this (this is an example structure):
[program:laravel-worker]
command=/usr/bin/php /path/to/your/project/artisan queue:work --once
process_name=%(program_name)s
numprocs=1
autostart=true
autorestart=true
user=www-data
stdout_logfile=/var/log/supervisor/laravel-worker.log
stderr_logfile=/var/log/supervisor/laravel-worker_err.log
By setting autorestart=true, Supervisor constantly monitors the worker process. If it crashes (due to an unhandled exception in your WelcomeEmail job, for example), Supervisor automatically restarts it, ensuring reliability.
Best Practices for Queueing Emails
While the database driver is simple for testing, for high-volume applications or mission-critical tasks like sending emails, developers often opt for more robust drivers like Redis or Beanstalkd. These systems offer better performance and scalability because they decouple the queue from the main application database.
Key Takeaways:
- Dispatch is Not Execution:
dispatch()only places a record in the queue table. - The Worker is Separate: The actual execution requires a separate, long-running process (the worker).
- Use Process Managers: Always deploy your workers using Supervisor or Systemd to guarantee background operation and automatic recovery.
By implementing a persistent worker managed by a process supervisor, you transform your queue from a manual task into a reliable, self-healing background service, ensuring your email notifications are sent reliably every time.