Belajar Laravel #16: Queue & Job — Antrian Pekerjaan di Latar Belakang

Sampai di episode #15, email & notification sudah bisa terkirim dari aplikasi Laravel. Tapi ada satu masalah yang baru saya sadari setelah mencobanya: saat user klik “kirim email”, dia harus menunggu proses email benar-benar selesai sebelum halaman berikutnya tampil. Kalau SMTP lagi lambat, user bisa terdiam beberapa detik di depan layar. Ternyata di Laravel ada solusi rapi untuk masalah ini: Queue. Ini yang saya catat saat mempelajarinya.

Analogi: Antrian Kasir di Supermarket

Bayangkan kasir yang melayani pembeli sekaligus menyeduh kopi untuk pembeli lain. Kalau kasir harus menunggu kopi matang, antrian di belakangnya akan menumpuk. Solusinya: kopi dikerjakan orang lain di belakang, kasir terus melayani. Dalam queue, pekerjaan berat (kirim email, proses gambar, integrasi API pihak ketiga) dipindah dari request HTTP ke job yang dikerjakan worker terpisah. User mendapat response cepat, pekerjaan berat jalan di latar belakang.

Konsep Dasar: Job, Worker, dan Driver

Tiga kata ini yang paling sering saya jumpai. Job = satu pekerjaan yang dikirim ke antrian. Worker = proses yang duduk di antrian lalu mengambil dan mengerjakan job. Driver = tempat job dititipkan selama menunggu — di database, Redis, Amazon SQS, atau bahkan synchron (langsung dikerjakan saat itu juga, default di environment development). Konfigurasinya ada di config/queue.php, dan pilihan aktifnya ditentukan lewat QUEUE_CONNECTION di file .env.

Membuat Job Pertama

Laravel menyediakan Artisan command khusus untuk membuat job:

php artisan make:job SendWelcomeEmailJob

File job-nya ada di app/Jobs/SendWelcomeEmailJob.php. Supaya job bisa masuk antrian, kelasnya harus mengimplementasikan interface ShouldQueue. Logika utamanya ditulis di method handle():

<?php

namespace App\Jobs;

use App\Mail\WelcomeMail;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Mail;

class SendWelcomeEmailJob implements ShouldQueue
{
    use Queueable;

    public function __construct(public string $userEmail) {}

    public function handle(): void
    {
        Mail::to($this->userEmail)->send(new WelcomeMail());
    }
}

Lalu di controller tinggal dispatch:

SendWelcomeEmailJob::dispatch($user->email);

Perhatikan constructor memakai public string $userEmail — ini PHP property promotion, jadi tidak perlu tulis assignasi manual. Nilai di constructor akan ikut disimpan (serialize) bersama job saat dikirim ke antrian.

Menjalankan Worker: Driver Database

Untuk produksi sederhana (misal di shared hosting), driver database sudah cukup. Laravel punya migration untuk tabel jobs, jadi tinggal jalankan:

php artisan queue:table
php artisan migrate
php artisan queue:work --tries=3

Command queue:work inilah “kasir” yang menunggu di antrian — dia akan memindahkan isi tabel jobs ke tabel failed_jobs kalau job terus gagal. Artinya worker harus jalan sebagai proses terus-menerus (di VPS: supervisor atau systemd service). Kalau memakai Redis, driver-nya ganti di .env jadi QUEUE_CONNECTION=redis, worker-nya tetap sama.

Job yang Berulang Gagal: Failed Jobs

Satu hal yang saya syukuri: Laravel mencatat job yang gagal total. Setelah 3 kali percobaan (default $tries), job dipindah ke tabel failed_jobs beserta exception-nya. Untuk melihat:

php artisan queue:failed

Dan untuk mengulang job yang sudah tercatat gagal: php artisan queue:retry all. Saya juga bisa menambah method failed(\Throwable $e) di dalam job — dipanggil otomatis saat job masuk failed queue, misal untuk mencatat log atau mengirim notifikasi ke admin.

Job Batching: Banyak Pekerjaan Sekaligus

Kadang saya perlu memproses banyak job sekaligus, misal 1.000 email newsletter. Laravel punya Bus::batch() untuk itu:

use Illuminate\Support\Facades\Bus;

Bus::batch([
    new SendWelcomeEmailJob('a@example.com'),
    new SendWelcomeEmailJob('b@example.com'),
])->name('newsletter-batch')
  ->then(function () {
      // semua job selesai
  })
  ->catch(function () {
      // ada job yang gagal total
  })
  ->dispatch();

Batch ini butuh tabel tambahan (bikin via php artisan queue:batches-table), tapi hasilnya sangat membantu: saya bisa tahu progress batch, dan callback then() hanya berjalan kalau semua job sukses.

Yang Saya Terapkan

Untuk proyek kecil di shared hosting, saya pakai driver database + cPanel cron menjalankan queue:work tiap menit (mode one-time lalu diulang supervisorless — paling sederhana). Untuk proyek yang benar-benar produksi, Redis + supervisor lebih masuk akal. Inti pelajarannya: apapun yang lambat dan tidak harus terjadi di depan user — kirim email, generate PDF, panggil API eksternal — jangan ditaruh langsung di request. Serahkan ke queue.


Sumber

Tinggalkan Balasan

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Situs ini menggunakan Akismet untuk mengurangi spam. Pelajari bagaimana data komentar Anda diproses