spiral/roadrunner-grpc
High-performance PHP gRPC server built on RoadRunner. Run PHP and Go services in one app with native gRPC compliance, TLS, middleware, Prometheus metrics, and protoc code generation. Map response error codes to PHP exceptions.
Architecture fit. Unchanged at the architectural level: this is still the PHP worker-side contract for the RoadRunner gRPC stack — a Go plugin terminates HTTP/2 + gRPC and dispatches decoded protobuf payloads to long-lived PHP workers implementing generated base classes. The package is a handler contract (Server, Context, Invoker, exceptions, interceptors), not a gRPC server. It remains a natural extension for a Laravel codebase already on RoadRunner and a runtime migration disguised as a library for a PHP-FPM/nginx estate.
What has changed across 3.8.0 → 3.8.1 is that the rename is now a two-package story, not one. 3.8.0 renamed spiral/roadrunner-grpc → roadrunner/grpc; 3.8.1 fixes require roadrunner/roadrunner instead of spiral/roadrunner. So the artifact we put in composer.json, the transitive runtime SDK it pulls in, our SBOM entries, allowlists, scanner rules, and internal docs all shift together. Architecturally neutral, but the blast radius on dependency bookkeeping has roughly doubled, and the rename is now visible one layer deeper into the graph than the previous assessment assumed. Critically, 3.8.0 was published with the old runtime dependency wired in — meaning the first release under the new name shipped a partially migrated dependency graph. Anything spiked or pinned against 3.8.0 is carrying a legacy reference and must be re-resolved.
Integration feasibility. Still mechanically straightforward — Composer install, grpc block in .rr.yaml, protoc + RoadRunner protoc plugin codegen, thin handlers, dedicated worker entrypoint. Three release-specific deltas now:
composer require roadrunner/grpc plus a transitive requirement on roadrunner/roadrunner. The critical unknown has widened: it is no longer only whether spiral/roadrunner-grpc is abandoned with a replace/alias — it is also whether spiral/roadrunner is abandoned/replaced by roadrunner/roadrunner, and whether the two share namespace (Spiral\RoadRunner\…) and class names. If either alias is missing, a monorepo can resolve both legacy and new packages, producing duplicate SDK classes under one namespace and a "which one am I actually running" failure that is painful to diagnose. Add a CI guard that fails on the presence of either legacy package.spiral/roadrunner-* packages (http/worker/cli). If roadrunner/grpc 3.8.1 now requires roadrunner/roadrunner while Octane still requires spiral/roadrunner-http, we face either a Composer conflict or a split-brain install of two runtime SDK generations. This is the single most likely way 3.8.1 breaks an existing Laravel app, and it is a broader migration than the gRPC package alone. Resolve it in a scratch branch before touching the pilot.roadrunner/roadrunner), the RoadRunner server line (explicitly including v3), and google/protobuf/grpc extensions must be validated as a set. Treat "supports RoadRunner v3" as a new matrix cell to test, not a free upgrade — and confirm 3.8.1 did not shift the minimum server version as a side effect of the dependency swap.With RoadRunner already in place, spike-to-first-endpoint remains days; without it, the RoadRunner migration stays on the critical path and dominates the estimate.
Technical risk. Still rated high on dependency-consensus grounds. The rename picture is now clearer but worse-informed:
Key questions.
spiral/roadrunner-grpc abandoned on Packagist with a replace/alias to roadrunner/grpc, and are namespaces/classes unchanged between the two?spiral/roadrunner abandoned/replaced by roadrunner/roadrunner, and do both define Spiral\RoadRunner\… classes at the same FQCNs?roadrunner/roadrunner, and does that constrain the RoadRunner server binary we can run? Did the minimum server version move?roadrunner/grpc 3.8.1 co-install with our current Laravel/Octane version, or does Octane's spiral/roadrunner-* family conflict? Is an Octane upgrade a prerequisite?.proto files, and what is the versioning and breaking-change policy? Protobuf does not enforce backward compatibility.grpc/grpc PHP extension, or a Go service) if it stalls?Stack fit. Unchanged: cleanest on Laravel + RoadRunner (Octane or native worker) with a service tier already talking to other internal services, gRPC surface isolated in its own worker entrypoint and config block, thin handlers over a shared domain layer. Poor fit remains FPM-only deployments, shared hosting, teams without proto/IDL experience, and browser/third-party-facing APIs. One new caveat: fit now depends on the Octane/RoadRunner package family being co-installable with the renamed SDK, not just on RoadRunner being present.
Migration path. Still additive — nothing gets migrated, and the release does not change that. Amendments:
spiral/roadrunner-grpc and spiral/roadrunner; swap composer.json to roadrunner/grpc and let 3.8.1 resolve roadrunner/roadrunner; diff composer.lock to confirm the legacy packages are gone, not merely shadowed; verify no namespace or class-name churn; add a CI check that fails if either legacy package reappears (direct or transitive); update internal docs, templates, and IDE snippets to the new names. Hours, not days — but skipping it means every later step inherits a stale reference. Do not upgrade 3.8.0 → 3.8.1 in place on a branch that was already running; re-resolve from a clean lock..proto, one unary method, one streaming method, health endpoint, Prometheus scraping, and a load test against the REST equivalent. Include an explicit Octane-compatibility check in the first two days. Output: latency/throughput/RSS numbers, a decision memo, and a confirmed, version-pinned support matrix.buf), versioning rules — before a second consumer exists.Explicit non-goal in phases 1–2 remains: do not replace working REST endpoints.
Compatibility. Enforce the matrix in CI and extend it with the release's new axis: PHP 8.2–8.4; RoadRunner server v3 and the previously validated 2024.x/2025.x line (test both until we decide to narrow); google/protobuf v4.x; grpc extension version; Laravel/Octane version; and now the resolved roadrunner/roadrunner version, recorded explicitly in the matrix rather than treated as a transitive detail. Pin the RoadRunner binary as an infrastructure artifact, never latest, and gate PHP package upgrades on a matching server release. Re-validate that protoc plugin and codegen output are byte-identical across both the rename and the 3.8.1 dependency swap — a silent regeneration diff after a package swap is an easy way to ship an unintended wire change.
Sequencing. Package rename + dual-alias audit (spiral/roadrunner-grpc, spiral/roadrunner) → clean-lock re-resolution on 3.8.1 → Octane co-installability check → runtime prerequisite (RoadRunner, incl. v3 validation) → toolchain (protoc plugin, codegen, buf lint) → observability (metrics, structured logs, worker health) → pilot endpoints (unary first, streaming second) → governance (proto versioning, deprecation) → broader adoption. Resist starting with streaming; it remains the highest-complexity path and the worst first demonstration.
Maintenance. Low code-volume maintenance, non-trivial version maintenance, and the rename bookkeeping cost is now larger than previously scoped: SBOM entries, dependency allowlists, vulnerability-scanner rules, internal wiki/template references, and pinned CI images may name both legacy packages. Generated stubs remain a build artifact with a reproducible pipeline, never hand-edited. Because the new package names start with effectively no dependent base — and 3.8.0 shipped with a dependency defect caught only in 3.8.1 — assume we are among the earliest production users of every 3.8.x release and will find regressions ourselves: pin, stage-soak, then promote. Budget recurring effort for the three-way version lock (wider server matrix, renamed SDK) and for proto schema hygiene as consumer count grows.
Support. Primary support remains the RoadRunner docs site plus SpiralScout maintainers via GitHub issues; no commercial SLA behind this package specifically (commercial support exists in the broader Spiral/RoadRunner orbit). The rename degrades informal support quality — external search results, blog posts, and Q&A point at differently-named packages, and answers will lag. 3.8.1 adds a specific support hazard: a build that fails on package resolution will tempt someone to "fix" it by reverting to spiral/roadrunner, reintroducing the dual-install condition. Compensate with an internal owner: one or two engineers designated for the gRPC layer, the toolchain, the runtime SDK pin, and the proto contracts, plus a short internal note covering both renames. Absent ownership, this layer decays into an unowned dependency nobody dares upgrade.
Scaling. Unchanged. The Go proxy handles connection management, multiplexing, and HTTP/2 termination; RoadRunner scales throughput by adding supervised workers, roughly linearly with CPU until PHP is the bottleneck. Size numWorkers against CPU and memory — each persistent worker holds a full Laravel bootstrap, so container limits need explicit accounting. Capacity-test streaming endpoints separately from unary traffic (long-lived connections, backpressure).
Failure modes to instrument and rehearse. (a) Silent worker death — every handler needs try/catch plus structured logging, and gRPC exception-to-google.rpc.Status mapping must be verified so client-side errors are diagnosable. (b) Memory growth per worker — track RSS against maxJobs, recycle deliberately. (c) State leakage between requests in long-lived workers — audit statics/singletons, reset request-scoped state per invocation. (d) Version skew — now with three failure axes: PHP SDK ↔ RoadRunner server (v3 vs. 2024.x/2025.x); legacy spiral/roadrunner-grpc ↔ roadrunner/grpc; and legacy spiral/roadrunner ↔ roadrunner/roadrunner, the last of which 3.8.0 demonstrably got wrong. Fail fast at startup with an explicit version assertion and legacy-package checks for both families. (e) Proto incompatibility at deploy boundaries — never deploy producer and consumer schema changes independently. (f) Unbounded streaming or missing deadlines — enforce deadlines on client and server. (g) Composer resolution failure at deploy time on an Octane/RoadRunner stack mid-rename — catch in CI, not in a release.
Ramp-up. Still 2–4 weeks to productivity and 2–3 months to real confidence, dominated by proto/IDL discipline and persistent-worker debugging rather than this package's API. The rename adds an onboarding wrinkle that 3.8.1 sharpens: new engineers will find the old package names in search results and older internal branches, and may find mixed old/new names in third-party tutorials. Mitigate with the pilot-as-reference-implementation, a template repo (proto layout, CI codegen, .rr.yaml, observability wiring, error-mapping helper) pinned to roadrunner/grpc 3.8.1+, an explicit roadrunner/roadrunner pin, and a specific RoadRunner server line; a one-paragraph "why the names changed" note covering both packages; and a working session on worker lifecycle. Under-investing in ramp-up remains the most common way a technically sound gRPC adoption stalls at one service.
How can I help you explore Laravel packages today?