spiral/roadrunner
RoadRunner is a high-performance PHP application server and process manager written in Go. It offers HTTP/2/3, gRPC, fCGI, queues, KV storage, and OpenTelemetry via plugins, serving as a powerful alternative to Nginx+FPM.
Architecture fit
roadrunner driver. Direct SDK use only makes sense if we want the plugin surface (queues, KV, gRPC, Temporal, locks, Prometheus/OTEL, Centrifugo), not for HTTP alone.github.com/roadrunner-server/roadrunner/v3, plugins on v6 Go contracts, api / api-go/v6 / api-plugins/v6 split out, goridge/v4, pool/v2. This widens the version matrix we must pin (binary major, SDK major, Octane major, Go plugin generation)./usr/bin/rr from the published image) is intact for HTTP, but the premise needs a caveat in the ADR — and the caveat now has a second dimension: a self-built binary is also a self-patched binary, and we inherit responsibility for Go toolchain CVEs.Integration feasibility
php artisan octane:install --server=roadrunner, .rr.yaml, multi-stage Docker build copying /usr/bin/rr from a pinned image tag. Prefer pinning by digest; the calendar-tag scheme is replaced by semver-style v3.x, so our Renovate rule must change from 2025.x patterns to v3 majors.spiral/roadrunner-worker / -http / -cli SDK v3 packages are released and Octane constrains to them, (c) Symfony Runtime has v3 support. If any of these is not yet true, the pilot pins to the latest v2025.x and v3 becomes a scheduled follow-on — do not start a new deployment on a major we know we will migrate off within twelve months.v2025.x, we must confirm whether a v2025.x build exists that carries the Go 1.27.3 fix. If it does not, "stay on the older major for a year" quietly converts into "run a known CVE for a year," and that changes the gate from a convenience question to a security-driven one. Resolve this before the pilot pin is chosen, not after.EOF-on-worker-start failure mode is unchanged: missing sockets extension, missing SDK package, or bad server.command. Bake the extension into the image and keep the CI boot smoke test.http.middleware now evaluates left to right; v5 lists must be reversed to preserve behavior. This is silent — no error, just different ordering.config.version removed; static pipelines require config.connection plus nested exchange/queue.envfile is now non-experimental, and a configured file must exist at startup or the server fails to boot.Upgrade: h2c no longer supported; cleartext HTTP/2 requires prior knowledge.dynamic_allocator.max_workers now counts workers above the base pool; any autoscaling tuning numbers recorded from v2025 are wrong for v3.Technical risk
crypto/x509, GO-2026-6809) is a Go-stdlib issue that no Composer audit tool will ever report. Our PHP-side security scanning says nothing about this binary. If it isn't in the Go/image scan path, it's invisible.proxy_ip_parser and rate_limiter swap relative position, IP-keyed rate limiting can key on attacker-controlled headers. Ordering must be explicit, reviewed, and covered by a test.proxy_ip_parser trusted-header selection (http.trusted_headers) — good hardening, but only if configured. Left permissive or misordered, X-Forwarded-For spoofing bypasses rate limits and pollutes audit logs.Retry-After) and Laravel can too. We must pick a system of record per concern or accept confusing double-counting and mismatched Retry-After semantics between edge and app.max_jobs / max_worker_memory / exec_ttl.2026-10-09 anomaly is explained — v3.0.0 is dated 2026-10-08 and supersedes v2025.1.13 (2026-04-17). The v3.0.1 security patch landing shortly after the major is a healthy signal: fast turnaround on a stdlib CVE is what a maintained project looks like. Dependents: 0 remains a package-family-split artifact. The modest opportunity score still argues for a pilot-gated decision, not an org-wide bet.Key questions
v2025.x and v3 becomes a scheduled upgrade, not a launch blocker.v2025.x build carrying Go 1.27.3? If not, does that override the "don't launch on an old major" preference and force the v3 pilot?crypto/x509 CVE is a low note or a page..rr.yaml and the binary pin, and what is the review standard for middleware ordering and trusted headers?proxy_ip_parser configured relative to rate_limiter?RateLimiter? Which layer owns 429s and Retry-After?Stack fit
--server=roadrunner) → RoadRunner Go server → PHP CLI workers. spiral/roadrunner and siblings arrive transitively; app code must not call them directly.COPY --from=ghcr.io/roadrunner-server/roadrunner:<pin> /usr/bin/rr. Pin by digest, with a documented re-pin cadence for patch releases (v3.0.x), separate from the major-tracking rule..rr.yaml is reviewed like code. Minimum review checklist now includes:
server.command, http.address, http.pool.*, http.request_body_limit, http.middlewares in the left-to-right order.proxy_ip_parser strictly before rate_limiter; zstd/gzip before static; headers last.http.trusted_headers explicitly enumerated — never default-permissive.rpc.listen bound to localhost/Unix socket only, using the Unix socket mode/owner/group attributes where supported rather than TCP.envfile present and mounted, or omitted entirely. Never declare a path that may not exist.logs.mode: production; gRPC Protoreg reflection off unless required.Upgrade: h2c.Migration path
v2025.x has the Go 1.27.3 fix. Decide v3 vs v2025.x for the pilot and record the reason. Everything downstream depends on this answer.envfile, re-baseline dynamic_allocator numbers, decide gzip vs zstd with fallback.v3.0.1 or later, never v3.0.0. Do not carry the pre-fix Go toolchain into the pilot as a known exception.storage/filesystem assumptions, uploads, session driver. Fix findings; add a CI lint rule where feasible.Compatibility
Sequencing
Octane/RR version gate (+ v2025.x CVE-backport check) → binary pin at v3.0.1+ + Docker image → .rr.yaml baseline and v3 middleware-order + trusted-headers review → Octane install + worker bootstrap → pool tuning → re-baseline autoscaling against new dynamic_allocator semantics → OTEL/Prometheus → load test vs FPM baseline → app-readiness fixes → canary → cutover → FPM decommission. CI gains a smoke job that boots rr serve and asserts a 200, a job asserting the compiled .rr.yaml middleware order matches an expected fixture, and a job that reports the embedded Go toolchain version for the pinned digest.
Maintenance
api, api-go/v6, and api-plugins/v6 for anyone writing or maintaining custom plugins — three more repos in the dependency graph, each with its own patch obligation..rr.yaml remains infrastructure config in app repos; it carries security-relevant knobs (trusted headers, proxy protocol, rate limiter, Unix socket permissions, TLS) and therefore needs a named owner and a review checklist, not just a reviewer.Support
Scaling
dynamic_allocator.max_workers now means workers above base pool, and idle-worker removal changed. v2025-era tuning notes are invalid for v3. Treat the new retry-on-acquire behavior as a latency-smoothing feature, not a capacity guarantee.max_jobs, max_worker_memory, exec_ttl) remains the primary leak containment. Set conservatively, tighten from observed RSS.Failure modes
rate_limiter ahead of proxy_ip_parser and turn IP limits into header-controlled no-ops. Caught only by an explicit ordering test.http.trusted_headers lets a client forge the key used for rate limiting and audit logging.envfile — hard boot failure if declared but absent; a container/ConfigMap mismatch now takes the service down at boot rather than at first request.Upgrade: h2c between LB and RR breaks silently after v3.request_body_limit, read_timeout, max_request_size required or uploads and slow endpoints fail in ways FPM never did.terminationGracePeriodSeconds must exceed longest request duration.Ramp-up
v2025.x, schedule the v3 upgrade as a distinct ticket with the same budget — and add the CVE-backport verification as a prerequisite.How can I help you explore Laravel packages today?