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)