How to run a sub batch for every job instance in a batch of Laravel? Check the image for quick clarification.
- Make sure all used job classes has Batchable trait.
- Use add() method of the batch() method to create your sub batch for that job instance of the main batch.
- You can add single job to every job instance of the batch using add() method.
- You can create a another batch or sub batch for every job instance of the batch.
Quick Example
$this->batch()->add(
array of job class instances
single job class instance |
enumerable or collection of job class instances
)
....
use Illuminate\Support\Collection;
....
class MainBatchJob implements ShouldQueue
{
use Queueable, Batchable;
.....
/**
* Execute the job.
*/
public function handle(): void
{
//Creating a sub job batch using Collection
$this->batch()->add(Collection::times(5, function($key){
return new SubJob;
}));
}
}
Full example
Imagine you have to a create mail campaigns for 5 products. Each product has mail subscribers. When you create a mail campaign for a product it should create a batch to send mail to all its subscribers.
First create two required jobs as PrepareMailCampaign and SendMailToSubscriber using below artisan command.
php artisan make:job PrepareMailCampaign
php artisan make:job SendMailToSubscriber
Open SendMailToSubscriber job class and add below code
- Accept product name and key (it may be user id, mailer id, etc.) via the constructor.
- Log product name and key
<?php
namespace App\Jobs;
use Illuminate\Bus\Batchable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Log;
class SendMailToSubscriber implements ShouldQueue
{
use Queueable, Batchable;
/**
* Create a new job instance.
*/
public function __construct(
public string $productName,
public string $key
)
{
//
}
/**
* Execute the job.
*/
public function handle(): void
{
Log::info("Complete Sending mail for
{$this->key} user - {$this->productName}" );
}
}
Open PrepareMailCampaign and add below code.
- Accept product name via the constructor.
- Add your sub batch which is mail sending batch in the handle() method.
<?php
namespace App\Jobs;
use Illuminate\Bus\Batchable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
class PrepareMailCampaign implements ShouldQueue
{
use Queueable, Batchable;
/**
* Create a new job instance.
*/
public function __construct(public string $productName)
{
//
}
/**
* Execute the job.
*/
public function handle(): void
{
Log::info("Complete Campaign - ". $this->productName);
$this->batch()->add(Collection::times(5, function($key){
return new SendMailToSubscriber($this->productName, $key);
}));
}
}
Open web.php file and add below code.
- Create a array to hold product names
- Create a empty array hold array of jobs for batch.
- Iterate products array and create batch.
- Execute the batch.
<?php
use App\Jobs\PrepareMailCampaign;
use Illuminate\Support\Facades\Bus;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
//Log request
Log::info("Received a get request on root route");
//List of products that require main campaigns.
$products = ['prod_1', 'prod_2', 'prod_3', 'prod_4', 'prod_5'];
//Create empty batch array to hold prepareMainCampaign jobs
$batch = [];
//Create the mailCampaign Batch
foreach($products as $product)
{
array_push($batch, new PrepareMailCampaign($product));
}
//Dispatch the batch
Bus::batch($batch)->dispatch();
});
Run two instances of queue workers using below artisan command.
php artisan queue:work
Logs:
- Sub batches are execute after completing the main batch.
- Sub batches are execute in order instead of executing randomly.
[2025-01-06 05:26:30] local.INFO: Received a get request on root route
//Completed the main batch
[2025-01-06 05:26:31] local.INFO: Complete Campaign - prod_1
[2025-01-06 05:26:33] local.INFO: Complete Campaign - prod_2
[2025-01-06 05:26:35] local.INFO: Complete Campaign - prod_3
[2025-01-06 05:26:37] local.INFO: Complete Campaign - prod_4
[2025-01-06 05:26:39] local.INFO: Complete Campaign - prod_5
//Completed the sub batch for product 1
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 1 user - prod_1
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 2 user - prod_1
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 3 user - prod_1
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 4 user - prod_1
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 5 user - prod_1
//Completed the sub batch for product 2
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 1 user - prod_2
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 2 user - prod_2
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 3 user - prod_2
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 4 user - prod_2
[2025-01-06 05:26:41] local.INFO: Complete Sending mail for 5 user - prod_2
....