← Semua pembelajaran / Laravel Nol → Enterprise
Fase 8 · FrankenPHP & RoadRunner

RoadRunner — pengantar

RoadRunner memisahkan server dari PHP: proses Go menerima permintaan, lalu menyerahkannya ke kumpulan proses PHP lewat pipa. Pemisahan itu membawa isolasi yang lebih kuat dan sederet plugin yang tidak ada di tempat lain.

Intisari

  • Satu biner Go yang mengelola kumpulan proses PHP CLI — bukan utas di dalam satu proses.
  • Dikonfigurasi lewat satu berkas .rr.yaml, per plugin.
  • Isolasi lebih kuat: satu worker yang crash tidak menyentuh worker lain, dan tidak butuh PHP thread-safe.
  • Ekosistem plugin: jobs (antrean), grpc, kv, metrics, temporal, centrifuge.
  • Bukan web server penuh: TLS dan berkas statis biasanya diserahkan ke Nginx atau load balancer di depannya.

Arsitektur

internet → (Nginx / ALB) → RoadRunner (Go)
                              ├── worker PHP #1  (proses CLI)
                              ├── worker PHP #2
                              ├── worker PHP #3
                              └── …
                           dihubungkan lewat pipa atau soket Unix

Perbedaannya dengan FrankenPHP ada di baris terakhir: RoadRunner tidak menanamkan PHP ke dalam dirinya. Ia menjalankan proses PHP terpisah dan berkomunikasi lewat pipa. Konsekuensinya berjalan ke dua arah — isolasi lebih baik, tapi ada biaya komunikasi antar proses dan jejak memori per worker yang lebih besar.

Konfigurasi minimal

version: "3"

server:
  command: "php psr-worker.php"

http:
  address: 0.0.0.0:8080

logs:
  level: info
  mode: production
./rr serve
./rr serve -c .rr.yaml
./rr reset                 # muat ulang worker dengan rapi
./rr workers -i            # pantau worker secara interaktif

./rr workers -i adalah alat diagnostik yang layak dihafal. Ia menampilkan tabel langsung berisi setiap worker: PID, status, jumlah permintaan yang sudah ditangani, dan pemakaian memorinya. Kebocoran memori langsung terlihat di kolom terakhir — dan kamu bisa melihat worker mana yang sedang macet.

Bentuk sebuah worker PHP

<?php
require __DIR__.'/vendor/autoload.php';

$worker = Spiral\RoadRunner\Worker::create();
$factory = new Nyholm\Psr7\Factory\Psr17Factory();
$psr7 = new Spiral\RoadRunner\Http\PSR7Worker($worker, $factory, $factory, $factory);

while (true) {
    try {
        $request = $psr7->waitRequest();      // ← blokir sampai ada permintaan

        if ($request === null) {              // server minta worker berhenti
            break;
        }
    } catch (Throwable $e) {
        $psr7->respond(new Nyholm\Psr7\Response(400));
        continue;
    }

    try {
        $psr7->respond(new Nyholm\Psr7\Response(200, [], 'Halo RoadRunner!'));
    } catch (Throwable $e) {
        $psr7->respond(new Nyholm\Psr7\Response(500));
        $psr7->getWorker()->error((string) $e);
    }
}

Bentuknya berbasis PSR-7, bukan superglobal. Untuk Laravel, Octane yang menjembatani keduanya, jadi kamu tidak menulis berkas ini sendiri — tapi mengenalinya menjelaskan kenapa perilaku RoadRunner terasa berbeda dari FrankenPHP dalam hal-hal kecil.

Plugin — bagian yang membedakan

PluginGunanya
httpHTTP/HTTPS/HTTP2/HTTP3, dengan middleware bawaan
jobsAntrean: AMQP, Kafka, SQS, NATS, Beanstalk, memori
grpcServer gRPC untuk PHP
kvPenyimpanan kunci-nilai: Redis, Memcached, BoltDB, memori
metricsEndpoint metrik bergaya Prometheus
temporalMesin alur kerja tahan gangguan
centrifugeWebSocket dan pesan real-time
serviceMenjalankan proses pendamping di bawah pengawasan RoadRunner

Plugin jobs adalah alasan sebagian tim memilih RoadRunner. Ia berarti satu proses yang sama bisa melayani HTTP dan memproses antrean, dengan konsumen antrean yang dikelola server — bukan proses queue:work terpisah yang harus dijaga sendiri. Untuk arsitektur kontainer, ini bisa berarti lebih sedikit jenis task yang perlu dijalankan dan dipantau.

Middleware HTTP bawaan

http:
  address: 0.0.0.0:8080
  max_request_size: 32       # MB
  middleware: ["gzip", "headers", "static"]

  static:
    dir: "public"
    forbid: [".php", ".htaccess"]

  headers:
    response:
      X-Powered-By: ""

RoadRunner bisa melayani berkas statis lewat middleware static, tapi kemampuannya lebih sederhana daripada web server penuh. Di lingkungan produksi yang serius, aset statis biasanya diserahkan ke CDN atau Nginx — dan itu memang pola yang disarankan.

Yang perlu diketahui sebelum memilih

KelebihanKekurangan
Tidak butuh PHP thread-safePerlu web server atau load balancer di depan untuk TLS
Isolasi antar worker sangat kuatJejak memori per worker lebih besar daripada per utas
Ekosistem plugin luasKonfigurasi lebih banyak yang harus dipahami
Kontrol pool sangat detailBerkas .rr.yaml jadi permukaan konfigurasi tersendiri
Dukungan Temporal dan gRPC kelas satuBerkas statis tidak sekuat web server penuh

Latihan: unduh biner rr, buat .rr.yaml minimal dengan worker PSR-7 di atas, dan jalankan ./rr serve. Buka ./rr workers -i di terminal kedua sambil mengirim permintaan, dan amati kolom jumlah permintaan serta memorinya bergerak.

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.