Belajar Symfony - Worker Mode: FrankenPHP & RoadRunner
Episode 22 of 27

Belajar Symfony - Worker Mode: FrankenPHP & RoadRunner

Mengganti model eksekusi tradisional dengan worker mode: memahami perbedaan PHP-FPM vs aplikasi yang hidup permanen, menjalankan Symfony dengan FrankenPHP dan RoadRunner, serta kapan memilih yang mana untuk production.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Selama 21 episode, aplikasi berjalan dengan model eksekusi klasik PHP: proses di-spawn per request (FPM). Episode 22 memperkenalkan model baru yang sedang naik daun di 2026: worker mode — aplikasi yang di-load sekali dan hidup terus, melayani banyak request.

Mengapa ini penting? Karena biaya terbesar request bukan kode-nya, melainkan bootstrap — inisialisasi container, load autoloader, build metadata. Worker mode membayar biaya itu sekali saja. Hasilnya: peningkatan performa yang signifikan tanpa menambah server, dan itu alasan utama ekosistem PHP bergerak ke arah ini.

Memahami Model Eksekusi

PHP-FPM: Born-per-Request

100%

Setiap request mem-bootstrap seluruh aplikasi: container, autoload, metadata. Konsisten dan aman (state tidak bocor antar request), tapi boros untuk beban tinggi.

Worker Mode: Long-Lived

100%

Aplikasi di-load sekali; request berikutnya tinggal diproses. Bootstrap tidak berulang — inilah sumber kecepatannya.

Symfony Runtime

Symfony Runtime adalah abstraksi yang membuat aplikasi bisa dijalankan di berbagai model eksekusi tanpa mengubah kode:

Install runtime
composer require symfony/runtime

Dengan runtime terpasang, public/index.php meminta runtime memilih runtime yang aktif. Kode aplikasi tidak berubah — hanya cara menjalankannya yang berbeda. Inilah yang membuat migrasi ke worker mode semulus mungkin.

FrankenPHP

FrankenPHP adalah app server PHP yang menanamkan PHP langsung di Caddy (Go). Menariknya: ia memakai model worker dengan cara yang automatic:

Install runtime FrankenPHP
composer require frankenphp/symfony-runtime

Kode (dengan PHP 8.4+ dan APP_RUNTIME=Runtime\\FrankenPHPRuntime) mengenali variabel environment FrankenPHP dan otomatis masuk worker mode:

.env untuk worker mode
APP_RUNTIME=Runtime\FrankenPHPRuntime
FRANKENPHP_WORKER=1

Run via image resmi:

Jalankan FrankenPHP
docker run -v .:/app -p 8080:80 dunglas/frankenphp:8.4

Keunggulan FrankenPHP:

AspekNilai
Setupcomposer require + env var — tanpa konfigurasi worker manual
HTTPSBawaan Caddy (auto Let's Encrypt)
TambahanDukungan WebSocket, Mercure, HTTP/3
IntegrasiResmi didukung Symfony (Symfony Runtime)

Untuk memaksimalkan cache opcode dalam mode worker, hindari opcache.validate_timestamps di dev — di production, set 0 (seperti episode 14).

RoadRunner

RoadRunner (ditulis Go oleh Spiral) adalah pendekatan berbeda: server Go memakai PHP sebagai worker dalam sub-proses:

Install RoadRunner
composer require spiral/roadrunner-cli
composer require spiral/roadrunner-symfony
vendor/bin/rr get

Konfigurasi .rr.yaml:

.rr.yaml
server:
    command: "php worker.php"
 
http:
    address: ":8080"
    pool:
        num_workers: 8

worker.php adalah entri point standar:

worker.php
use Symfony\Component\Runtime\SymfonyRuntime;
use Symfony\Component\HttpKernel\KernelInterface;
 
require_once dirname(__DIR__) . '/vendor/autoload_runtime.php';
 
return function (array $context): KernelInterface {
    $kernel = new App\Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
 
    return $kernel;
};

Lalu:

Jalankan RoadRunner
./rr serve

Keunggulan RoadRunner:

AspekNilai
Pool managementnum_workers eksplisit, restart otomatis
EkosistemMemori & lifecycle worker terkontrol penuh
TambahanGRPC, jobs (queue), KV (Redis) terintegrasi

Kapan Memilih Mana

FaktorFrankenPHPRoadRunner
Kemudahan setupSangat mudah (1 command)Sedang (file .rr + worker)
Kontrol workerOtomatisManual (num_workers)
Fitur tambahanHTTPS, WebSocket, MercureGRPC, jobs, KV
Paling cocokSymfony murni, cepat jalanPlatform dengan banyak kebutuhan non-HTTP

Tip

Aturan praktis: mulai dari FrankenPHP jika kalian murni membutuhkan HTTP cepat dan otomatis. Pilih RoadRunner jika project membutuhkan GRPC, job queue, atau kontrol pool yang presisi. Keduanya bisa hidup berdampingan — lihat episode 23 untuk packaging Docker-nya.

Worker Mode dan Messenger

Worker mode bukan hanya untuk HTTP — ia berpasangan sempurna dengan Messenger (episode 10): worker yang sama bisa melayani HTTP dan mengkonsumsi antrian. Dengan RoadRunner misalnya, eksekutor HTTP dan jobs diatur dalam satu server:

.rr.yaml — HTTP + jobs
http:
    address: ":8080"
 
jobs:
    consume:
        - "app.queue"

Ini menyederhanakan operasional: satu proses, satu health check, satu unit scaling.

Common Pitfalls

  • State bocor antar request — di worker mode, variabel statis & global tidak reset antar request. Symfony aman (container stateless), tapi kode custom dengan global/static harus disterilkan.
  • File upload & streaming — pastikan handler reset() atau state per-request dibersihkan di akhir request (Symfony Runtime menangani ini).
  • Perilaku dev vs prod — opcache + cache container berlaku lama di worker; selalu cache:clear/restart worker saat deploy.

Penutup

Pada episode 22 ini, kalian telah memahami dan menjalankan worker mode.

Inti yang harus dibawa pulang:

  • PHP-FPM spawns per request; worker mode melayani banyak request dari satu proses.
  • Symfony Runtime mengabstraksi model eksekusi tanpa mengubah kode.
  • FrankenPHP (Caddy + PHP): worker otomatis, HTTPS bawaan, setup 1 menit.
  • RoadRunner (Go + PHP): kontrol pool manual, GRPC/jobs/KV terintegrasi.
  • Hati-hati state global & lifecycle opcache di worker mode.

Di episode 23 selanjutnya kita mempackaging semuanya: Docker & Deployment CI/CD — Dockerfile multi-stage, compose untuk dev/prod, migrasi & cache warmup saat deploy, dan pipeline GitHub Actions. Sampai jumpa di episode 23!

Belajar Symfony - Worker Mode: FrankenPHP & RoadRunner | Belajar Symfony