Let's continue with the previously created application for database based queues.

We’ll use MySQL database table for queue jobs. To do this, generate the queue table use the following artisan commands.

php artisan queue:table
php artisan migrate

The above migration creates a new jobs table for queue based jobs in out DB.

Let’s update our .env file to use the database. Change QUEUE_DRIVER from sync to database.

Refresh http://localhost:8000/mail and check mailtrap, nothing will show up. Check out your jobs table though:

The job is ready for a queue worker to pick it up and process it. On the command line, you can run:

php artisan queue:work

My output looks like this:

$ php artisan queue:work
[2018-03-28 22:35:35][1] Processing: App\Jobs\SendOrderEmail
[2018-03-28 22:35:36][1] Processed:  App\Jobs\SendOrderEmail

and the email is now in mailtrap. queue:work will continue to run until you kill it with CTRL+C.

You can go ahead and kill it for now.

Of course you won’t want to SSH into your production server and run php artisan queue:work every time you want to process jobs. You would instead install Supervisor on your production machine running the queue to run the queue workers at all times. If the queue process dies for any reason, Supervisor will restart it. For the rest of this tutorial, however, we’ll manually run the queue so we can see exactly what is going on.

Failed Jobs

If you look into the jobs table now, it should be empty. 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. Install it with artisan:

php artisan queue:failed-table
php artisan migrate

Now you have a failed_jobs table. What would cause a job to fail? If the job throws an exception then the job fails and is retried. Once the job has been retried for the max allowed limit of retries or of time, it can now be taken out of the queue and put into the failed_jobs table. Let’s manually recreate this.

Add this so it is the first line of the handle function of SendOrderEmail:

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

That will of course throw an exception. Now let’s send another email by visiting http://localhost.8000/mail. This time, let’s add some more parameters to our queue workers. Run:

php artisan queue:work --tries=3

In the terminal you’ll see something like this:

$ php artisan queue:work --tries=3
[2018-03-28 22:46:04][2] Processing: App\Jobs\SendOrderEmail
[2018-03-28 22:46:04][3] Processing: App\Jobs\SendOrderEmail
[2018-03-28 22:46:04][4] Processing: App\Jobs\SendOrderEmail
[2018-03-28 22:46:04][4] Failed:     App\Jobs\SendOrderEmail
If you look in the database you’ll see the failed job is no longer in the jobs table but is in the failed_jobs table.

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

php artisan queue:failed

This shows all the failed jobs that are no longer in your queue. Luckily, if you resolve the exception you can re-add the job to the queue from the command line.

Go back to SendOrderEmail.php and remove the exception you added. Now on the command line run:

php artisan queue:retry 1

1 is the ID of the failed_job. This pushes the job back onto the queue. Work the queue again:

php artisan queue:work --tries=3

The job was now processed successfully and your email is in mailtrap!

Warning: When you start your queue worker (php artisan queue:work --tries=3), the application is loaded into memory and the process lives indefinitely until you kill it.

This means that if you make a change in your application code (for example, you fix an exception), it will appear like your queue worker is still reading the old code (it’s in memory).

You need to kill the queue daemon and restart it, recommend restart every time you deploy code. Even better, add a queue restart command to your deploy script to automate it.