DEV Community

Adnan Mumtaz
Adnan Mumtaz

Posted on

Advance Laravel: Dispatch Jobs from Cron Jobs in Laravel (Part 1)

This is a common pattern that can be used to avoid long-running cron jobs and process the tasks faster with less memory and better control over the processes.

Let's assume you have to send the newsletter to more than 500 users every day/month.

I am assuming you already have a basic knowledge of Laravel and PHP

Lets create a new Project.

composer create-project larave/laravel

After creating a project lets create a separate command call it NewsLetterCommand

Run this command in the root directory of your newly created project.

php artisan make:command NewsLetterCommand

Newly file will be created by the laravel to do the heavy stuff.


<?php

namespace App\Console\Commands;

use App\Models\User;
use Illuminate\Console\Command;

class NewsLetterCommand extends Command
{
    protected $signature = 'newsletter:send';
    protected $description = 'Send Newsletter to Users.';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {

        $users = User::all();
        foreach ($users as $user) {
            // Send mail to user
            \Mail::raw('Sending emails ', function ($message) {
                $message->subject('Newsletter ');
                $message->from('no-reply@example.com', 'Website Name');
                $message->to('test@example.com');
            });


        }
    }
}

Let's assume we have 500 users in our database and sending an email will take almost 1-2 sec per user depending on the service you are using. Sending an email to 500 users will take approximate 8 minutes.

Now you got the picture in the whole process our script and processor will be busy for the next 8 to 10 minutes.

Now you got the big picture, assume you are encoding a video or running some CPU intensive process which takes around 5-10 minutes each.

How to avoid this common pitfall.

Here comes Laravel Jobs to rescue. Rather than doing all the stuff in a single process divide it into multiple sub-process.

Let's create a Laravel Job.

php artisan make:job SendNewsLetterJob

Laravel will create a SendNewsLetterJob stub for us.


<?php

namespace App\Jobs;

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

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

    public $user;

    public function __construct(User $user)
    {
        $this->user =  $user;
    }


    public function handle()
    {
        \Mail::raw('Sending emails ', function ($message){
            $message->subject('Newsletter ');
            $message->from('no-reply@example.com', 'Website Name');
            $message->to($this->user->email);
        });

    }
}

Now we have everything set up let's dispatch the job from the cron job. From the "NewsLetterCommand" lets dispatch the job.


php


namespace App\Console\Commands;

use App\Jobs\SendNewsLetterJob;
use App\Models\User;
use Illuminate\Console\Command;

class NewsLetterCommand extends Command
{
    protected $signature = 'newsletter:send';
    protected $description = 'Send Newsletter to Users.';

    public function __construct()
    {
        parent::__construct();
    }

    public function handle()
    {

        $users = User::all();
        foreach ($users as $user) {
            // Send mail to user
            dispatch(new SendNewsLetterJob($user));

        }
    }
}


This approach is easier to debug and trace errors.
It will save us some time, even we can concurrently send multiple processes. It is also easier to test.

In the next part of this tutorial, we will refactor the code and will apply some job-throttling. 

Please excuse brevity and Typos. 

Top comments (0)