Melampaui model request-response klasik PHP: concurrency dengan Fibers dan Swoole, pemrosesan background lewat Laravel Queues dengan Redis/SQS dan worker, penjadwalan dengan cron dan schedule, serta streaming response untuk data dalam jumlah besar.

Model PHP klasik sederhana: request masuk → proses → response keluar → proses mati. Episode 20 membuka dimensi baru: bagaimana PHP menangani pekerjaan yang lama, banyak, atau paralel — mulai dari pemrosesan background (email, notifikasi, import data) hingga concurrency sungguhan dengan Fibers dan Swoole.
Mengapa penting? Aplikasi produksi selalu punya pekerjaan yang tidak bisa selesai dalam satu request: mengirim 10.000 email, memproses file CSV raksasa, memanggil API eksternal yang lambat. Jika semua itu dilakukan sinkron di request, pengguna menunggu lama dan server tersumbat. Queues + worker adalah jawaban standar industri — dan memahami ini membedakan aplikasi amatir dari aplikasi profesional.
Bandingkan dua pendekatan:
| Pendekatan | Alur | Masalah |
|---|---|---|
| Sinkron | Request → email 10.000 pengguna → response | Pengguna menunggu menit; request timeout |
| Async (queue) | Request → masukkan job ke queue → response cepat | Worker memproses di latar belakang |
Aturan penentu: jika tugas >1-2 detik, tidak harus selesai segera, atau bisa gagal dan perlu retry — itu kandidat queue. Contoh: email, notifikasi, thumbnail/resize gambar, import/export data, sinkronisasi API eksternal, webhook.
Laravel menyediakan queue system bawaan. Konfigurasi koneksi:
QUEUE_CONNECTION=redis
REDIS_HOST=127.0.0.1Definisikan job:
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Mail;
class KirimEmail implements ShouldQueue
{
use Queueable;
public function __construct(
public array $recipients,
public string $subject,
) {}
public function handle(): void
{
foreach ($this->recipients as $email) {
Mail::to($email)->send(new WelcomeMail($this->subject));
}
}
}Kirim job ke queue (response langsung cepat):
KirimEmail::dispatch($daftarEmail, "Selamat datang!");Proses job dengan worker (proses daemon):
php artisan queue:work redis --tries=3Worker jalan terus memproses job dari Redis. Tuning penting: --tries untuk retry saat gagal, --timeout membatasi durasi per job, dan --max-jobs/--max-time agar worker restart berkala (antisipasi memory leak). Di produksi, worker dijaga hidup dengan Supervisor.
[program:queue-worker]
command=php /var/www/toko/artisan queue:work redis --sleep=3 --tries=3 --max-time=3600
directory=/var/www/toko
autostart=true
autorestart=true
numprocs=4sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl statusnumprocs=4 menjalankan 4 worker paralel — throughput 4x untuk job yang CPU-bound ringan. Setiap restart otomatis jika worker crash atau melebihi --max-time.
| Backend | Kelebihan | Kapan dipakai |
|---|---|---|
| Redis | Cepat, self-hosted | Standar lokal/self-managed |
| Amazon SQS | Managed, otomatis scale, tanpa server | Cloud AWS |
| Database | Tanpa infra tambahan | Proyek kecil |
Untuk job terjadwal (bukan per-event), pakai schedule Laravel — satu entry cron, sisanya di kode:
namespace App\Console\Commands;
use Illuminate\Console\Command;
class LaporanHarian extends Command
{
protected $signature = "laporan:harian";
public function handle(): void
{
// generate & kirim laporan
}
}use Illuminate\Support\Facades\Schedule;
Schedule::command("laporan:harian")->dailyAt("07:00");
Schedule::command("backup:database")->weekly()->sundays()->at("02:00");Satu baris di crontab sistem yang memicu scheduler:
* * * * * cd /var/www/toko && php artisan schedule:run >> /dev/null 2>&1Kelebihan pendekatan ini: jadwal hidup di kode (versi-controlled), bukan tersebar di crontab server.
PHP 8.1 menghadirkan Fibers — primitif untuk cooperative concurrency di dalam satu proses PHP. Fiber berguna untuk menunggu I/O (HTTP call, database) secara paralel tanpa multi-proses:
use Fiber;
$fiberA = new Fiber(fn () => httpGet("https://api-a.example.com/data"));
$fiberB = new Fiber(fn () => httpGet("https://api-b.example.com/data"));
$fiberA->start();
$fiberB->start();
$dataA = $fiberA->getReturn();
$dataB = $fiberB->getReturn();Swoole (dan Open Swoole) melangkah lebih jauh: menulis ulang model runtime PHP menjadi event-driven + coroutine, memungkinkan ribuan koneksi bersamaan dalam satu proses — fondasi aplikasi real-time dan WebSocket.
Swoole\Coroutine\run(function () {
$server = new Swoole\HTTP\Server("0.0.0.0", 9501);
$server->on("request", function ($req, $res) {
$res->end("Halo dari Swoole!");
});
$server->start();
});Warning
Swoole bukan PHP biasa — ia mengubah lifecycle (satu proses untuk banyak request) sehingga kebiasaan "state per request" tidak berlaku lagi. Jangan terjun ke Swoole tanpa kebutuhan nyata (real-time, high concurrency). Untuk 90% aplikasi Laravel, queue + worker sudah jauh lebih dari cukup dan jauh lebih sederhana untuk di-maintain.
Untuk data besar (export CSV, report), streaming mengirim data bertahap alih-alih menunggu semuanya jadi:
public function exportCsv()
{
$filename = "laporan-" . date("Ymd") . ".csv";
return response()->streamDownload(function () {
$handle = fopen("php://output", "w");
fputcsv($handle, ["Nama", "Email", "Total"]);
// query chunk-by-chunk, bukan semua sekaligus
User::query()->chunkById(1000, function ($users) use ($handle) {
foreach ($users as $u) {
fputcsv($handle, [$u->nama, $u->email, $u->orders_sum_total]);
}
});
fclose($handle);
}, $filename);
}chunkById memproses 1000 baris per batch — memori tetap terkendali meski jutaan baris. Ini perpaduan streaming + batch processing yang menjadi standar untuk export data.
--tries dan backoff.queue:work), bukan dalam request.Inti yang harus dibawa pulang:
queue:work) → Supervisor menjaga worker tetap hidup.Schedule::command) + satu crontab → jadwal hidup di kode.chunkById untuk export data besar tanpa membebani memori.Di episode 21 selanjutnya kita memikirkan arsitektur: Microservices & Monolith Modular — membandingkan modular monolith dan microservices, peran API Gateway, message queues untuk event-driven, lalu DTO, service layer, dan dependency injection container sebagai praktik menata kode yang tumbuh.