In web applications, certain tasks consume a lot of time, like sending an email. With Laravel, you can create queued jobs that can be executed in the background. Then your users will get the response on the screen or from API quicker.
In this first chapter we will show you how to run jobs in the queue on your local web server with Database driver. In Laravel we can enqueue jobs, events, and closures.
The database driver is acceptable if the queue workload is expected to be small and sufficient to handle the traffic. It is a simple queue solution that does not require additional requirements and may be cheaper than other options like Redis or Amazon SQS.
Send Verification Email Demo
- For this demonstration we will take the default Laravel installation with Laravel Breeze which will provide all the scaffolding to send email verification.
laravel new test-project cd test-project/ composer require laravel/breezephp artisan breeze:install -q blade
Do not forget to configure database settings in your
.env
file and run migrations.
- As for inbox we chose to use Mailtrap.io platform to capture emails.
Credentials will be provided as you create your email testing inbox:
Now configure your mail credentials in the .env
file:
.env
MAIL_MAILER=smtpMAIL_HOST=sandbox.smtp.mailtrap.ioMAIL_PORT=2525MAIL_USERNAME=<YOUR_USERNAME>MAIL_PASSWORD=<YOUR_PASSWORD>MAIL_ENCRYPTION=tls
- Now update the
User
model by uncommenting theMustVerifyEmail
contract, and adding theimplements MustVerifyEmail
statement to theUser
class.
app/Models/User.php
use Illuminate\Contracts\Auth\MustVerifyEmail; class User extends Authenticatable implements MustVerifyEmail
Now go to the /register
URL to create a new user and when the form is submitted an email should show up in your testing inbox.
In this case verification, email is being sent immediately (synchronously). To send email using queues (asynchronously) we need to make a few changes.
- Create a
jobs
table where all queue-ables will be stored.
php artisan queue:tablephp artisan migrate
And update the environment file
.env
from
QUEUE_CONNECTION=sync
to
QUEUE_CONNECTION=database
If you forget to do that all your enqueued jobs and events will be run synchronously and won't benefit from queues.
- In
app/Providers/EventServiceProvider.php
comment outSendEmailVerificationNotification::class,
line:
protected $listen = [ Registered::class => [ // SendEmailVerificationNotification::class, ],];
We won't be using the default listener for the Registered
event and will wrap email-sending functionality in a separate job.
Create a new SendEmailVerification
job using this command:
php artisan make:job SendEmailVerification
Then update all its contents with the following:
app/Jobs/SendEmailVerification.php
namespace App\Jobs; use App\Models\User;use Illuminate\Bus\Queueable;use Illuminate\Contracts\Auth\MustVerifyEmail;use Illuminate\Contracts\Queue\ShouldBeUnique;use Illuminate\Contracts\Queue\ShouldQueue;use Illuminate\Foundation\Bus\Dispatchable;use Illuminate\Queue\InteractsWithQueue;use Illuminate\Queue\SerializesModels; class SendEmailVerification implements ShouldQueue{ protected $user; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct(User $user) { $this->user = $user; } public function handle(): void { if ($this->user instanceof MustVerifyEmail && ! $this->user->hasVerifiedEmail()) { $this->user->sendEmailVerificationNotification(); } }}
Then update the store
method of the RegisteredUserController
by adding the SendEmailVerification::dispatch($user);
statement to dispatch a job to send email verification.
app/Http/Controllers/Auth/RegisteredUserController.php
use App\Jobs\SendEmailVerification; // ... public function store(Request $request): RedirectResponse{ // ... event(new Registered($user)); SendEmailVerification::dispatch($user); Auth::login($user); return redirect(RouteServiceProvider::HOME);}
Now when a new user is registered this job will be put into Queue to be processed by Queue Worker. Try it. Email should not be delivered yet this time, because we do not have a queue worker running. If we inspected the jobs
table in our database we would see that there's a new entry for this task.
The payload field has all the required data to process this job.
- You may run the worker using the
queue:work
artisan command. It will start a queue worker and process new jobs as they are pushed into the queue.
php artisan queue:work
Once the
queue:work
command has started, it will continue to run until it is manually stopped or you close your terminal.
Now email will be delivered and the jobs
table should be empty. It holds only pending jobs and removes them as soon as the job is complete (email is sent in our case).
Queue Worker options
Worker sleep duration
When jobs are available on the queue, the worker will keep processing jobs with no delay in between jobs. However, the sleep
option determines how many seconds a worker will "sleep" if there are no jobs available. Of course, while sleeping, the worker will not process any new jobs:
php artisan queue:work --sleep=3
This is useful when you have an empty queue for longer periods and is more efficient than constantly polling queue driver for new jobs.
Processing jobs for a given number of seconds
The --max-time
option may be used to instruct the worker to process jobs in the given number of seconds and then exit. This option may be useful when combined with Supervisor so that your workers are automatically restarted after processing jobs for a given amount of time, releasing any memory they may have accumulated:
php artisan queue:work --max-time=3600
Max attempts
If one of your queued jobs is encountering an error, you likely do not want it to keep retrying indefinitely. Therefore, Laravel provides various ways to specify how many times or for how long a job may be attempted.
One approach to specifying the maximum number of times a job may be attempted is via the --tries
switch on the Artisan command line. This will apply to all jobs processed by the worker unless the job being processed specifies the number of times it may be attempted:
php artisan queue:work --tries=3
More options can be seen by issuing this command:
php artisan help queue:work
Parallel processing
To process jobs in parallel you may run multiple queue:work
instances. This can be useful to speed up short jobs like sending emails to process them faster.
Queue workers & Deployment
Queue workers store the booted application state in memory. As a result, they will not notice changes in your code base after they have been started. So, during your deployment process, be sure to restart your queue workers, by running the queue:restart
command.
php artisan queue:restart
Queue workers & Development
While developing your application you may run the queue:listen
command. It is significantly less efficient than the queue:work
command because queue:listen
boots the application for every iteration, but you don't have to manually restart the worker when you want to reload your updated code or reset the application state.
What's next?
To keep the queue:work
process running permanently in the background, we should use a process monitor such as Supervisor to ensure that the queue worker does not stop running. Let's move to another chapter to set up Supervisor for this purpose.
We can now stop the queue:work
process and let's move to another chapter to set up Supervisor for this purpose.
Should that read "your code base after they have been started" instead of "your case base after they have been started" ?
thanks, fixed
! $this->user->hasVerifiedEmail() with this case this is not working
How about giving an use case of something less trivial then sending emails?
Hello! Is the example supposed to be run on local Ubuntu machine or on AWS EC2 server instance?
Be carefull with parallel queues, sometimes it can messup order fo jobs if you use the same queue for batch jobs or jobs in general where order matters.
Please in this code :
Is it obligated to dispatch the event
Registered
before the job can be dispatched ? Are the two related ? Or could I just dispatch de job without firing the event to receive the mail ?In short: no, it is not obligated, you can dispatch job immediately. In case you have more jobs on certain event, i.e. when user registers you can add them in EventServiceProvider.
what is the best way to set the queue run on server When we tried to setup using cron , It crashes the app after some time and show max_user_connections error. Cron is set to run every minute with following command php artisan queue:work --queue=default --sleep=3 --tries=3 Error SQLSTATE[HY000] [1203] User database_laravel already has more than 'max_user_connections' active connections (SQL: select * from
users
whereid
= 2 limit 1) we already have max_user_connections set to 500We want to use this queue for sending emails
Hi, we have a full course on exactly this case:
https://laraveldaily.com/lesson/laravel-queues-server/workers-setup-email
This is the url of this course chapter
Oh my, something did not copy right then and I did not notice. Sorry!
What I wanted to add was this: https://laraveldaily.com/course/laravel-queues
As it covers a lot of configuration and potential issues. But at the same time - it might be beneficial to move into
Redis
instead of database :)in laravel 11 there is no app/Providers/EventServiceProvider.php how do i comment out SendEmailVerificationNotification::class
I believe that there's no EventServiceProvider.php on Laravel 11,so no need of commenting out. I just went ahead and created Jobs/SendEmailVerification