Laravel Cronjob and Queue: Make your task Automate


Hello folks,
I hope you are doing well. Today am writing this blog because of my past hustle, which I had in my current project. I was working on a project which requires to make email automation but, the Cronjob was not enough. Yes, it was a bit difficult so, I just, Googled it but could found a proper solution than I started working on trial and error method. After some attempts, I finally figured out one approach, which is a combination of Cronjob and Queue. This approach can be useful for many scenarios so, thought why not share this with you guys. So here I am sharing this let’s just dive into this.

We will learn it with one example. Let’s say we want to share one email to all customers who have ordered some goods from your site in the last 24 hours.

Now for that, you can say we can do it with single Cronjob or single Queue, correct? But wait a minute have you thought about the server part? One Cronjob take to many calls on the server but, the Queue works fine. But what if something wrong happens on Queue or Cronjob? Yeah! that 500 error which can come to us at any time in our life without even asking before entering, right? 😀 So to cover up all these issues, we will use the combination of Queue and Cronjob.

The first thing we will do is add Cronjob in kernel.php file, in schedule function.

$schedule->command('schedule:email')->cron('0 1 * * *');

The above sentence means the cron job will run every day at 1 AM. you can find more about the variance of cronjob here.

The next step is to add the Queue. To add the Queue, we need to run, below command.

php artisan make:job OrderEmail

I have given the name ‘OrderEmail’ of Queue. You can add anything to your wish. Now it will create a folder name ‘jobs’ and a file named ‘OrderEmail.php’ inside it in our app folder. Now let’s see our code for that file. We will add the code for sending emails to the customer.

<?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 DB;
use View;
use Log;

class ReviewEmail24 implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
    protected $data, $email;
    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($data, $email)
    {
        $this->data = $data;
        $this->email = $email;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        try{    
            if ($this->email != '') { 
                    $customer = DB::table('users')->where('id', $this->data->user_id)->first();

                    $subject = $this->email->subject;
                    $content = $this->email->content;

                    $sender_name = 'Chandni Soni';
                    $sender_email = 'sender@email.com';
                    $headers .= "From: " . $sender_name . "<" . $sender_email . ">\n";

                    // headers for attachment
                    $headers .= "MIME-Version: 1.0\n" . "Content-Type: multipart/mixed;\n" . " boundary=\"{$mime_boundary}\"";

                    mail($customer->email, $subject, $content, $headers);
                    DB::table('users')->where('id', $this->data->id)->update(array('email_send' => 1));
                
                echo "Done";
                Log::info('cronjob with queue: completed');
            }
        } catch(\Exception $e) {
            Self::failed($e);
        }
    }

    /**
     * The job failed to process.
     *
     * @param  Exception  $exception
     * @return void
     */
    public function failed($e) {

        $subject = 'Review email queue Failed';
            
        $html_body = '';
        $html_body .= "<br />";
        $html_body .= "<b> Message: </b> " . $e->getMessage() . " <br />";
        
        $sender_name = 'Chandni Soni';
        $sender_email = 'sender@email.com';
        $headers .= "From: " . $sender_name . "<" . $sender_email . ">\n";
        
        mail('your@email.com', $subject, $html_body, $headers);
        if( $send_mail ) {
            echo 'true';
            Log::error('true');
        } else {
            echo 'false';
            Log::error('false');
        }
        Log::error('cronjob with queue: failed ' . $e->getMessage());
    }
}

Now that our Queue is ready, we will add the ‘ScheduleEmail.php’ file to the App\Console\Commands folder.

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Jobs\OrderEmail as OrderEmail;
use Log;
use DB;

class ScheduleReview extends Command {

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'schedule:email';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Cron Job for send email to our customer';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct() {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle() {
        try{
            Log::info('Cronjob Start. Current Time: ' . date('Y-m-d h:i:s a'));
            $users = DB::table('users')->select('id','order_date')
                    ->where('email_send', 0)
                    ->whereRaw('order_date > DATE_SUB(NOW(), INTERVAL 24 HOUR)')
                    ->get();
                   
            Log::info('total form values array: ' . count($data->toArray()) );
            if (count($users) > 0) {
                $email = array(
                            'subject' => 'Email for Order',
                            'content' => 'Here you can put any content of your wish'
                            );
                if($email != ''){
                    foreach ($users as $data) {
                        dispatch(new OrderEmail($data, $email));
                    }
                }
            }

        } catch (\Exception $e) {
            Log::error('cronjob: failed ' . $e->getMessage());
        } 


        echo 'Cronjob Done';
        
        Log::info('Cronjob Done. Current Time: ' . date('Y-m-d h:i:s a') . ' Timezone is: ' . date_default_timezone_get() );
    }

}

So now, the final step is we need to install the Cronjob into our server so it can perform its magic. For that, we need to redirect to our project folder in cmd and run below command:

crontab -e

This open a file with lots of comment on that. You need to add your Cronjob in that file, and to do this, You need to write a bellowing line on that file.

* * * * * php /path/to/your/project/artisan schedule:run 1>> /dev/null 2>&1

And You are good to go. Isn’t it a pretty easy one?
Hope this will help you.
Keep Learning
Keep Codding 🙂

4 thoughts on “Laravel Cronjob and Queue: Make your task Automate

  1. Hello I am so grateful I found your web site, I really found you by accident, while I was searching on Aol for something else, Regardless I am here now and would just like to say cheers for a remarkable post and a all round enjoyable blog (I also love the theme/design), I don’t have time to read it all at the minute but I have saved it and also added your RSS feeds, so when I have time I will be back to read a great deal more, Please do keep up the excellent job.

    Like

  2. Hello! This is my first visit to your blog! We are a group of volunteers and starting a new initiative in a community in the same niche. Your blog provided us useful information to work on. You have done a outstanding job!

    Like

Comments are closed.

Create a website or blog at WordPress.com

Up ↑

Design a site like this with WordPress.com
Get started