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.
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.
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
User
model by uncommenting the MustVerifyEmail
contract, and adding the implements MustVerifyEmail
statement to the User
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.
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.
app/Providers/EventServiceProvider.php
comment out SendEmailVerificationNotification::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.
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).
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.
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
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
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 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
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.
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.