Tutorial Laravel 12 Job Batching: Implementasi, Progress, dan Error Handling
Bayangkan Anda perlu kirim email ke 5.000 pengguna sekaligus, atau proses 1.000 gambar setelah upload. Kalau dijalankan satu per satu lewat queue biasa, Anda tidak tahu kapan semuanya selesai, dan tidak bisa jalankan aksi “setelah semua beres”.
Job Batching di Laravel menyelesaikan masalah ini. Artikel ini membahas cara kerjanya, implementasi lengkap dengan contoh kode, dan cara handle error dalam batch.
Apa Itu Job Batching?
Job Batching memungkinkan Anda mengelompokkan beberapa job ke dalam satu batch, lalu mendefinisikan callback yang dijalankan:
- Saat semua job berhasil (
then) - Saat ada job yang gagal (
catch) - Saat semua job selesai (berhasil atau gagal) (
finally)
Setup: Membuat Tabel Batch
php artisan make:batches-table
php artisan migrate
Ini membuat tabel job_batches yang menyimpan status setiap batch.
Membuat Job yang Batchable
Job harus implement ShouldQueue dan gunakan trait Batchable:
<?php
namespace AppJobs;
use AppModelsUser;
use AppMailPromotionMail;
use IlluminateBusBatchable;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
use IlluminateFoundationBusDispatchable;
use IlluminateQueueInteractsWithQueue;
use IlluminateSupportFacadesMail;
class SendPromotionEmail implements ShouldQueue
{
use Batchable, Dispatchable, InteractsWithQueue, Queueable;
public function __construct(
private User $user
) {}
public function handle(): void
{
// Cek apakah batch sudah di-cancel
if ($this->batch()->cancelled()) {
return;
}
Mail::to($this->user)->send(new PromotionMail());
}
}
Mengirim Batch
use AppJobsSendPromotionEmail;
use IlluminateSupportFacadesBus;
$users = User::where('subscribed', true)->get();
$batch = Bus::batch(
$users->map(fn ($user) => new SendPromotionEmail($user))->toArray()
)->then(function (Batch $batch) {
// Dijalankan saat semua job berhasil
Log::info("Batch selesai: {$batch->totalJobs} email terkirim.");
})->catch(function (Batch $batch, Throwable $e) {
// Dijalankan saat ada job yang gagal
Log::error("Batch error: {$e->getMessage()}");
})->finally(function (Batch $batch) {
// Selalu dijalankan saat batch selesai (berhasil atau tidak)
Cache::forget('promotion-batch-running');
})->name('Kirim Email Promosi')
->allowFailures() // batch tetap lanjut meski ada job gagal
->dispatch();
// Simpan ID batch untuk monitor progress
return $batch->id;
Monitor Progress Batch
Ambil info batch berdasarkan ID:
use IlluminateSupportFacadesBus;
$batch = Bus::findBatch($batchId);
// Info yang tersedia
$batch->id;
$batch->name;
$batch->totalJobs;
$batch->pendingJobs;
$batch->failedJobs;
$batch->processedJobs(); // totalJobs - pendingJobs
$batch->progress(); // 0-100 persen
$batch->finished(); // apakah sudah selesai
$batch->cancelled(); // apakah di-cancel
Contoh endpoint API untuk polling progress:
Route::get('/batches/{batchId}/progress', function (string $batchId) {
$batch = Bus::findBatch($batchId);
if (!$batch) {
return response()->json(['error' => 'Batch tidak ditemukan'], 404);
}
return response()->json([
'progress' => $batch->progress(),
'total' => $batch->totalJobs,
'processed' => $batch->processedJobs(),
'failed' => $batch->failedJobs,
'finished' => $batch->finished(),
]);
})->middleware('auth');
Cancel Batch
$batch = Bus::findBatch($batchId);
$batch->cancel();
Job yang belum diproses akan skip sendiri karena pengecekan $this->batch()->cancelled() di awal method handle().
Batch dengan Job Berantai
Anda bisa chain batch: jalankan batch kedua setelah batch pertama selesai:
Bus::batch([
new ProcessImages($product),
new GenerateThumbnails($product),
])->then(function (Batch $batch) use ($product) {
// Setelah gambar dan thumbnail selesai, generate sitemap
GenerateSitemap::dispatch();
})->dispatch();
Praktis: Batch untuk Impor CSV
Skenario umum: impor data dari file CSV besar.
<?php
namespace AppJobs;
use IlluminateBusBatchable;
use IlluminateBusQueueable;
use IlluminateContractsQueueShouldQueue;
class ImportCsvRow implements ShouldQueue
{
use Batchable, Queueable;
public function __construct(private array $row) {}
public function handle(): void
{
if ($this->batch()->cancelled()) return;
Product::updateOrCreate(
['sku' => $this->row['sku']],
['name' => $this->row['name'], 'price' => $this->row['price']]
);
}
}
// Di controller
$rows = CsvParser::parse($file);
$jobs = collect($rows)->map(fn ($row) => new ImportCsvRow($row));
$batch = Bus::batch($jobs->toArray())
->name('Import Produk')
->allowFailures()
->dispatch();
return redirect()->route('imports.progress', $batch->id);
Baca Juga
- Notification di Laravel 12: Email, Database, dan Channel Kustom
- Apa Itu Event dan Listener di Laravel 12
Butuh tim untuk implementasi background processing di aplikasi Laravel Anda? Lihat layanan pengembangan aplikasi kami.
Artikel Lainnya di Kategori Laravel
9 November 2025
Apa Itu Laravel Volt dan Bagaimana Cara Kerjanya
Kalau Anda pernah pakai Livewire di Laravel, mungkin sudah tahu betapa nyamannya bikin komponen reaktif tanpa harus tulis JavaScript. Laravel Volt membawa pengalaman itu selangkah lebih jauh dengan sintaks single-file component yang lebih bersih. Artikel ini menjelaskan apa itu Laravel Volt, bagaimana cara kerjanya, dan di mana Volt cocok dipakai. Apa Itu Laravel Volt? Laravel […]
Baca Artikel9 November 2025
Tutorial PostgreSQL di Laravel: Setup, JSONB, dan Full-Text Search
Laravel secara default menggunakan MySQL. Tapi kalau proyek Anda butuh fitur seperti JSON columns yang lebih canggih, full-text search bawaan, atau JSONB, PostgreSQL adalah pilihan yang solid. Artikel ini membahas cara setup PostgreSQL di Laravel, termasuk konfigurasi, perbedaan dengan MySQL, dan fitur-fitur PostgreSQL yang bisa dimanfaatkan langsung dari Eloquent. Instalasi dan Konfigurasi Pastikan extension PHP […]
Baca Artikel
Laravel 9 November 2025
Routing di Laravel: Panduan Lengkap dengan Contoh Kode
Routing adalah pintu masuk semua request di Laravel. Sebelum request sampai ke controller atau logika apapun, dia harus melewati router dulu. Memahami cara kerja routing akan membuat kamu lebih mudah membangun struktur aplikasi yang rapi dan mudah di-maintain. Konsep Dasar: Bagaimana Request Diproses Saat browser mengirim request ke GET /posts, Laravel membaca file routes/web.php, mencari […]
Baca ArtikelIngin Membaca Artikel Lainnya?
Temukan lebih banyak insight dan tips tentang teknologi dan bisnis digital.
Lihat Semua Artikel