Ahmed Ashraf

Laravel version 8 will be released soon with a feature a lot of us were waiting for Jobs Batching. it allows you to dispatch a set of jobs in one batch and keep an eye on them and take action when any failure happens or when all pass.

Prerequisites

First, you need to run queue:batches-table artisan command to get the migration file of job_batches. also, you can change the table name by setting table value in queue.php

<?php

'batches' => [
    'table' => 'custom_jobs_batching_table_here'
]

How to dispatch

The Bus class has a batch() method that takes an array of jobs and return Batch object.

$batch = Bus::batch([
    new FirstJob(),
    new SecondJob(),
    new ThirdJob(),
])->dispatch();

Batch Object has a set of very nice properties that gives you very good insights about the batch and what is happening with its jobs.

{
   "id":"909db655-ed38-4739-89ea-ca6c1b13a5a0",
   "totalJobs":4,
   "pendingJobs":4,
   "processedJobs":0,
   "progress":0,
   "failedJobs":0,
   "createdAt":"2020-05-21T14:13:53.000000Z",
   "cancelledAt":null,
   "finishedAt":null
}

You can store the batch id anywhere to query it later and take any actions based on batch status.

Get batch by ID

The Bus class provides findBatch() method that takes batch_id and returns either Batch object or null

$batch = Bus::findBatch("909db655-ed38-4739-89ea-ca6c1b13a5a0")

Callbacks

Bus::batch() provides some functions as callbacks when

1 - then -> all jobs succeed

2 - catch -> any of the jobs failed

3 - finally -> whatever happens, it will run

Bus::batch([
   // jobs here
])
->then(function(Batch $batch){
  info('Batch ['.$batch->id.'] has been finished succesfully');
})
->catch(function(Batch $batch){
  info('Batch ['.$batch->id.'] failed to process all jobs');
})
->finally(function(Batch $batch){
   info('Batch ['.$batch->id.'] finished proccessing');
})

CLI Progress

Now after we explored the feature. I'll show you a quick example of something I always do in my projects and it's now very easy to do.

Let's say we want to dispatch some jobs and see their progress while running

// app/Console/Commands/CreateServerCommand.php

public function handle() {
  server = \App\Server::create(['name' => $this->argument('name')]);

  $batch = Bus::batch([
    new CreateServer($server),
    new UpdateKernel($server),
    new ProvisionScripts($server),
    new CreateDefaultSite($server),
  ])->dispatch();

  $progress = $this->output->createProgressBar(100);
  while (($batch = $batch->fresh()) && !$batch->finished()) {
      $progress->setProgress($batch->progress());
      sleep(0.5);
  }
  $progress->finish();
}

See how it's easy. we just run in a loop unless batch is finished. and in the loop we sleep for half second and then check if progress updated

Now this is how it looks when you run it

job-batching-progress

at

21 May 2020

Want to be updated with Laravel and other fun related stuff I'm doing. Just Subscribe