Mempelajari plugin queue dan jobs RoadRunner: mengonfigurasi pipeline dengan driver Redis, AMQP, dan SQS, mendorong job background seperti email dan laporan dari aplikasi, serta menulis consumer worker yang memproses dan melakukan ack atau reject task.

Setelah di episode 10 kita menyimpan data dengan KV, pada episode kali ini kita memindahkan pekerjaan ke background: plugin queue & jobs RoadRunner. Email notifikasi, laporan PDF, sinkronisasi data, webhook — semua tugas yang tidak boleh memperlambat respons HTTP — kita kirim ke antrian dan diproses oleh worker khusus.
Mengapa episode ini penting? Karena inilah cara aplikasi PHP modern memisahkan fast path (merespons user) dari slow path (kerja berat). Dan karena RoadRunner mengelola konsumsi antrian di level server Go, kalian tidak perlu daemon queue terpisah seperti yang biasa dilakukan Laravel/Beanstalkd.
Dua konsep yang perlu dibedakan:
Kelebihan RoadRunner: satu binary mengelola HTTP dan jobs — tidak ada supervisor terpisah untuk daemon queue.
Plugin jobs mendukung banyak driver: redis, amqp, sqs, beanstalk, dan boltdb. Contoh tiga pipeline:
jobs:
pool:
num_workers: 4
max_worker_memory: 128
consume:
- queue: "emails"
pipeline: "redis-emails"
- queue: "reports"
pipeline: "amqp-reports"
pipelines:
redis-emails:
driver: redis
config:
queue: emails
prefetch: 10
amqp-reports:
driver: amqp
config:
addr: amqp://guest:guest@localhost:5672/
queue: reports
exchange: reports
sqs-uploads:
driver: sqs
config:
key: ""
secret: ""
endpoint: https://sqs.us-east-1.amazonaws.com
queue: uploadsconsume memberi tahu server queue mana yang harus dikonsumsi dan oleh pipeline mana. Setiap pipeline bisa memakai pool berbeda — beban email tidak boleh mengganggu pemrosesan laporan.
Dari sisi PHP, pakai package spiral/roadrunner-jobs:
composer require spiral/roadrunner-jobsuse Spiral\RoadRunner\Jobs\Jobs;
$jobs = new Jobs($rpc);
// Pilih pipeline
$queue = $jobs->connect('redis-emails');
// Buat task dengan payload
$task = $queue->create(
'email.send',
['to' => 'user@example.com', 'template' => 'welcome'],
);
// Option opsional
$task->withDelay(5); // tunda 5 detik
$task->withPriority(2); // prioritas
// Kirim
$queue->push($task);connect('redis-emails') memakai nama pipeline dari config. create() menerima nama job (bebas) dan payload. push() mengirimnya ke antrian via RPC — eksekusi dilakukan pipeline, bukan oleh worker HTTP.
Consumer adalah worker PHP biasa — file consumer.php yang dijalankan pipeline. Pakai package spiral/roadrunner-jobs sisi consumer:
<?php
declare(strict_types=1);
use Spiral\RoadRunner\Jobs\Consumer;
use Spiral\RoadRunner\Jobs\Serializer\JsonSerializer;
use Spiral\RoadRunner\Worker;
require __DIR__ . '/vendor/autoload.php';
$consumer = new Consumer(Worker::create(), new JsonSerializer());
while ($task = $consumer->waitTask()) {
try {
$payload = $task->getPayload();
if ($payload['template'] === 'welcome') {
sendWelcomeEmail($payload['to']);
}
$task->ack();
} catch (\Throwable $e) {
$task->error('Gagal memproses: ' . $e->getMessage());
}
}Siklus hidup task penting:
| Aksi | Arti |
|---|---|
ack() | Job selesai sukses — dihapus dari antrian |
error() | Job gagal — dicatat, masuk statistik, tidak di-redeliver |
fail() | Job gagal dan akan di-redeliver (retry) |
requeue() | Kembalikan ke antrian dengan delay tertentu |
| (tidak dipanggil) | Worker mati sebelum menjawab — job di-redeliver otomatis |
Tip
Untuk job yang boleh retry dengan backoff, gunakan $task->requeue($delay). Untuk job yang tidak boleh retry (misal payload invalid), gunakan error() — jangan buang resource dengan retry tanpa batas.
Karena job bisa di-redeliver (misal worker mati setelah memproses tapi sebelum ack), setiap job harus idempoten — mengeksekusinya dua kali tidak boleh merusak apa pun. Contoh: sebelum mengirim email, cek di KV store apakah email:sent:{task_id} sudah ada:
$taskId = $task->getHeader('id') ?? $task->getId();
$doneKey = 'job:done:' . $taskId;
if ($cache->get($doneKey)) {
$task->ack();
continue;
}
sendEmail($payload['to']);
$cache->set($doneKey, true, 3600);
$task->ack();Gejala umum dan solusinya:
| Gejala | Penyebab | Solusi |
|---|---|---|
| Job tidak pernah diproses | Pipeline tidak terdaftar di consume | Pastikan pipeline ada di daftar consume |
connection refused Redis | Redis tidak jalan | Cek Redis dan addr pipeline |
| Worker jobs macet | Consumer tidak memanggil ack/error | Selalu akhiri task dengan salah satu |
| Job duplikat | Retry tanpa idempotensi | Terapkan pola idempotent di atas |
Statistik antrian bisa dilihat lewat ./rr jobs:list dan detail per job — kita kombinasikan dengan metrics di episode 12.
Pada episode 11 ini, kalian telah menguasai queue & jobs.
Inti yang harus dibawa pulang:
spiral/roadrunner-jobs via RPC.ack/error/requeue.consume menentukan alur kerja.Di episode 12 selanjutnya, kita belajar metrics & Prometheus — membuka endpoint /metrics, mendefinisikan counter, gauge, dan histogram kustom, lalu memvisualisasikan latensi request dan kesehatan pool di dashboard. Sampai jumpa di episode 12!