Queuing systems can be considered as a buffer where the data is stored and processed in the background to maintain the processing speed of the application. Different actions like sending emails, firing API requests etc. can be deferred so as to speed up the process and provide a smooth user experience. Suppose a system where a functionality sends notifications to around thousands of users, the service cannot wait for all the emails or notifications to be sent and then process further. This is where queuing comes to the rescue, all the emails are queued and sent in the background so the service does not wait and move forward..

Setup Overview

In a Laravel project, queue is formed of a job, the task to be run and a worker that runs the job. The queue configuration lies in the config/queue.php file. Here, we want emails to be queued so, the task to be run is sending emails. So, assuming that the project is setup and runnning, we need to create a mail class by simply running php artisan make:mail TestMail. Thus we have a file TestMail.php in the “Mail” directory. Add the email sending code in this file and create the mailable to be sent.

Queue Configuration

By default, we have the QUEUE_CONNECTION configuration in the .env file as follows:
QUEUE_CONNECTION = sync

A queue driver manages how to run a queued job, identifies if the jobs failed or succeeded and retries failed jobs if handled. We have queue drivers like sync, database, redis, beanstalkd etc that are supported by Laravel. The sync driver is the default one and it runs the queued jobs within the existing process, so it actually does not form a queue as the queued jobs run immediately. The database driver stores the queued jobs in the database. Sync is not recommended for production as it does not help the performance by setting up the queue. The database driver queues the jobs and helps improve performance and user experience. We will be using the database driver for the explanation of queueing emails in our example. However, the database driver is not quite efficient and not the best driver to prove performance with a lot of queuing.

So, first of all, we need to configure the driver so in the .env file modify the queue connection configuration and make it as follows:
QUEUE_CONNECTION = database

Also, configure the SMTP server settings for email sending. By default, Laravel uses Mailtrap.io server so that emails are sent to the Mailtrap inbox instead of users’ inbox or spam during the development process.

Now, as the database driver stores the jobs in the database, we generate a table for it by running: php artisan queue:table and then migrate it using php artisan migrate.

Queue logic

Now, to queue the mails, one can simply implement the interface ShouldQueue in the mail created. This means that suppose we have a mail class(in the app\mails directory) viz OfferMail to send mail about the new offer to all the users we just implement the ShouldQueue class.

Once we have implemented the logic, Laravel provides a queue worker that processes the jobs as they are pushed into the queue. For this, you may run php artisan queue:work Artisan command.

Suppose, instead of implementing the ShouldQueue interface in the mail class, we want to create a job for sending emails then follow the steps given below:

  • Create a mail class
    • For example, we want to send an offer email to the users of a shopping website, we create a mail by running php artisan make:mail OfferMail. The following class will be generated in the app\Mails directory.
  • Create a queue job
    • For creating a new job file, run php artisan make:job SendEmailJob
    • This will create a class SendEmailJob.php in the Jobs directory. Now add the code to it as follows:

How does the Queue Worker work?

By definition, workers are simple PHP processes that run in the background and extract jobs from the storage space and run them in reference to the configuration options. When the command php artisan queue:work is run, Laravel creates an instance of the application and executes the jobs. Thus, the instance will be created only once and the jobs will be executed with the same instance. Thus, the following must be considered: