Laravel 9 Queue Beginner to Advanced Example Tutorial

Hello Artisan

In this Laravel 9 queue tutorial, i will show you a simple laravel app that explain step by step how to use Laravel Queue and how to run Laravel Queue with redis and database driver. I will show you database as well as Redis queue connections with Laravel 9 version.

So if you don't know how to send email or notification using Laravel queue then this tutorial is going to the best example to learn how to send email and nofication using Laravel queue. So this example will help you to learn Laravel 9 queue to send email.

In this laravel 9 redis and database queue tutorial you will learn a bit more about queue and how to work with redis connection. In this tutorial i’ll create a simple demo Laravel 9 app that shows us how we can use queues in Laravel using the database connection and as well as the redis connection.

Now lets start our Laravel 9 queue tutorial. I will explain step by step to complete this laravel 9 queue tutorial from scratch. You have to just follow this below step. 

 

Step 1 : Download Fresh Laravel 9

I will start from scratch. So we have to download fresh laravel 9 app. To download it, run below command.

composer create-project --prefer-dist laravel/laravel example-app

 

Recommended: Upload Large CSV File using Queue Job Batching in Laravel

 

Step 2 : Create Model and Migration

To complete this Laravel 9 queue tutorial, i will use Order model. So we need some order to create laravel queue tutorial. For this reason i need factory also to insert some dummy data quickly.

php artisan make:model Order -fm

 

After running this command we will get orders migration file and OrderFactory. So open both file and paste it.

database/migrations/create_orders_table.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateOrdersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('orders', function (Blueprint $table) {
            $table->id();
            $table->string('name', 100);
            $table->integer('item_count')->unsigned();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('orders');
    }
}

 

Now run php artisan migrate command to save it into databse.

 

Step 3:  Add Dummy Records

In this we need to add some dummy records to create laravel 9 queue example tutorial. So open order factory and paste below code in it.

database/factories/OrderFactory.php

use App\Order;
use Faker\Generator as Faker;

$factory->define(Order::class, function (Faker $faker) {
    return [
        'name' => $faker->name,
        'item_count' => rand(1,10),
    ];
});

 

Now open terminal and paste this

php artisan tinker
//then
factory(App\Order::class, 50)->create();
//
exit

 

Step 4:  Create Order Mail

In this step, I will create Oder mail to send email to users using firstly database queue connection and then redis queue connection. To create this email i will use markdown mail. So run below command to create it.

php artisan make:mail OrderShipped --markdown=emails.orders.shipped

 

Now go to Mailtrap and setup your mail connection.

app/Mails/OrderShipped.php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

use App\Order;

class OrderShipped extends Mailable
{
    use Queueable, SerializesModels;

    public $order;

    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    public function build()
    {
        return $this->markdown('emails.orders.shipped');
    }
}

 

now we need to modify the emails/orders/shipped.blade.php file like this

resources/views/emails/orders/shipped.blade.php

 

Step 5:  Create Route

Now we need to create our route to send email in laravel with laravel queue. So paste this below code

routes/web.php

Route::get('test', 'MailController@index');

 

Now create a mail controller to write index method.

php artisan make:controller MailController

 

Now open mail controller and create an index function in your controller like this:

app/Http/Controllers/MailController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Mail;
use App\Mail\OrderShipped;
use App\Order;

class MailController extends Controller
{
    public function index() {

        $order = Order::findOrFail( rand(1,50) );

        $recipient = 'hello@example.com';

        Mail::to($recipient)->send(new OrderShipped($order));

        return 'Sent order ' . $order->id;
    }
}

 

Now open your browser and paste this url and hit enter button. Then you will see the below email in your mailtrap inbox.

 

URL
http://localhost:8000/test

 

then go to mailtrap and you should see your mail.

laravel-9-queue-tutorial-with-database-connection

 

Step 6: Setup Queue

Neat, we’re all set to go. Our application can send email, but still it’s not using queues. To demonstrate how to use queue in laravel, let’s create a job table that can be dispatched to a queue.

php artisan make:job SendOrderEmail

 

now open this file and paste this below code.

app/jobs/SendOrderEmail.php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

use Illuminate\Support\Facades\Mail;
use App\Mail\OrderShipped;
use App\Order;
use Log;

class SendOrderEmail implements ShouldQueue
{
	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

	public $order;

	public function __construct(Order $order)
	{
		$this->order = $order;
	}

	public function handle()
	{
		$recipient = 'hello@example.com';
		Mail::to($recipient)->send(new OrderShipped($this->order));
		Log::info('Emailed order ' . $this->order->id);
	}
}

 

Now time to rewrite our MailController to dispatch SendOrderEmail job instead of sending the email directly. So open and rewrite it like below

app/Http/Controllers/MailController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use Illuminate\Support\Facades\Mail;
use App\Jobs\SendOrderEmail;
use App\Order;
use Log;

class MailController extends Controller
{
    public function index() {

        $order = Order::findOrFail( rand(1,50) );
        SendOrderEmail::dispatch($order);

        Log::info('Dispatched order ' . $order->id);
        return 'Dispatched order ' . $order->id;
    }
}

 

Now reload this below url. Then you should see same message in your mailtrap browser that is sending via Laravel Queue.

 

URL
http://localhost:8000/test

 

and open your Log file you will see the below log info:

storage/log/laravel.log

[2020-05-15 22:22:18] local.INFO: Emailed order 20
[2020-05-15 22:22:18] local.INFO: Dispatched order 20

 

Step 7 : Setup Database Queue

 

Now we are going to use laravel 9 database queue coonection to send email. Now looking at your .env file and update it sync to database.

Let’s use a real queue to send email now. Run below command to create queue table

php artisan queue:table
php artisan migrate

And open .env and change QUEUE_CONNECTION from sync to database.

.env

QUEUE_CONNECTION=database

 

The job is ready for us to make a queue work and to pick it up and process it. run:

php artisan queue:work

 

And reload this url

 

URL
http://localhost:8000/test

 

Then you will see the output looks like this:

[2020-05-15 22:35:35][1] Processing: App\Jobs\SendOrderEmail
[2020-05-15 22:35:36][1] Processed:  App\Jobs\SendOrderEmail

and you will get mail from queue in your mailtrap mailbox.

 

Step 8 : Find Out Failed Jobs

If you see the jobs table now, it must be empty. You know that every time a job is processed, it is removed from the jobs table. What if something goes wrong? We’ll need a failed jobs table to handle failed job. 

php artisan queue:failed-table
php artisan migrate

 

now add this to check failed job in below path

app/jobs/SendOrderEmail.php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

use Illuminate\Support\Facades\Mail;
use App\Mail\OrderShipped;
use App\Order;
use Log;

class SendOrderEmail implements ShouldQueue
{
	use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

	public $order;

	public function __construct(Order $order)
	{
		$this->order = $order;
	}

	public function handle()
	{
		$recipient = 'hello@example.com';
		Mail::to($recipient)->send(new OrderShipped($this->order));
		Log::info('Emailed order ' . $this->order->id);
        throw new \Exception("I am throwing this exception", 1);
	}
}

 

Now let’s send another email by visiting http://localhost.8000/test. This time, let’s add some more parameters to our queue workers. Run:

php artisan queue:work --tries=3

 

In the terminal you should see something like this:

laravel-queue-example-with-redis

 

If you see in the database you’ll see the exception in our failed jobs table.

laravel-redis-tutorial

 

Go ahead and stop queue:work with CTRL+C. Run the command:

php artisan queue:failed

 

It shows all the failed jobs that are no longer in your queue.

failed-job-laravel-queue

 

Go back to SendOrderEmail.php and remove the exception you added.

throw new \Exception("I am throwing this exception", 1);

 

Now on the command line run:

php artisan queue:retry 1

 

Here 1 is the ID of the failed_job. It pushes the job back onto the queue. Run the queue again:

php artisan queue:work --tries=3

 

Now this time the job was processed successfully and your email is in mailtrap!

 

Step 9 : Setup Redis

Firstly run below command to install Redis via composer.

composer require predis/predis

 

In the above example we sent mail using laravel queue with database connection. But now we will send mail with the connection of Redis. Now time to setup redis in our machine. So install redis in your machine and after running redis in your machine follow below step.

.env

QUEUE_CONNECTION=redis

 

Now open database.php file and go to the bottom and make changes like below.

 'redis' => [

        'client' => env('REDIS_CLIENT', 'predis'),
 ],

 

Now start your redis server and check like below. I am using windows 10.

127.0.0.1:6379> PING
PONG
127.0.0.1:6379>

 

Read also : How to Set Limit Login Attempts in Laravel 7

 

Now redis and everything is set to go. Why we should use Redis for our Laravel queue connection? Redis offers us clustering and rate limiting. Let’s look at an example of rate limiting from laravel docs.

 

Open up your SendOrderEmail job and rewrite it to the following:

app/jobs/SendOrderEmail .php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Mail;
use App\Mail\OrderShipped;
use App\Order;
use Log;

class SendOrderEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $order;

    public function __construct(Order $order)
    {
        $this->order = $order;
    }

    public function handle()
    {
        // Allow only 2 emails every 1 second
        Redis::throttle('any_key')->allow(2)->every(1)->then(function () {

            $recipient = 'hello@example.com';
            Mail::to($recipient)->send(new OrderShipped($this->order));
            Log::info('Emailed order ' . $this->order->id);

        }, function () {
            // Could not obtain lock; this job will be re-queued
            return $this->release(2);
        });
    }

}

 

Read also: Laravel 9 Upload CSV File Example Without Packages

 

In the line Redis::throttle('any_key')->allow(2)->every(1)->then() I am using the Redis::throttle command and passing in any_key. We could pass in any key we want. Redis will take and remember the key.

Now let’s send another email by visiting

 

url
http://localhost.8000/test

 

Now this time, email is sent by Redis connection.

 

Facebook Github
A web enthusiastic, a self-motivated full-stack software engineer from Dhaka, Bangladesh with experience in developing applications using Laravel , React and Vue js