baldinof / roadrunner-bundle
A RoadRunner worker as a Symfony Bundle
Package info
github.com/Baldinof/roadrunner-bundle
Type:symfony-bundle
pkg:composer/baldinof/roadrunner-bundle
Fund package maintenance!
Requires
- php: >=8.1
- psr/log: ^2.0 || ^3.0
- spiral/goridge: ^4.0
- spiral/roadrunner: ^2023.1.0 || ^2024.1.0 || ^2025.1.0 || ^3.0
- spiral/roadrunner-http: ^4.0
- spiral/roadrunner-worker: ^3.0.0
- symfony/config: ^5.4 || ^6.0 || ^7.0 || ^8.0
- symfony/dependency-injection: ^5.4 || ^6.0 || ^7.0 || ^8.0
- symfony/http-kernel: ^5.4 || ^6.0 || ^7.0 || ^8.0
- symfony/yaml: ^5.4 || ^6.0 || ^7.0 || ^8.0
Requires (Dev)
- blackfire/php-sdk: ^1.21
- doctrine/doctrine-bundle: ^2.1.1 | ^3.0
- doctrine/mongodb-odm: ^2.2
- doctrine/orm: ^2.7.3 | ^3.0
- mikey179/vfsstream: ^1.6.8
- nyholm/psr7: ^1.2
- phpspec/prophecy: ^1.11
- phpspec/prophecy-phpunit: ^2.0
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^9.6
- sentry/sentry-symfony: ^4.5 || ^5.0
- spiral/roadrunner-grpc: ^3.0.0
- spiral/roadrunner-kv: ^4.0
- spiral/roadrunner-metrics: ^3.2.0
- symfony/framework-bundle: ^5.4 || ^6.0 || ^7.0 || ^8.0
- symfony/runtime: ^6.0 || ^7.0 || ^8.0
- symfony/validator: ^6.0 || ^7.0 || ^8.0
- symfony/var-dumper: ^6.0 || ^7.0 || ^8.0
- symfony/var-exporter: ^6.0 || ^7.0 || ^8.0
Suggests
- nyholm/psr7: For a super lightweight PSR-7/17 implementation
- spiral/roadrunner-cli: For easy installation of RoadRunner
- symfony/proxy-manager-bridge: For doctrine re-connection implementation
Provides
None
Conflicts
- doctrine/doctrine-bundle: <2.1.1
- sentry/sentry-symfony: <4.5.0
- spiral/roadrunner-metrics: <3.0.0
- symfony/proxy-manager-bridge: <5.4
- symfony/runtime: <6.4
Replaces
None
- 3.x-dev
- 3.5.0
- 3.4.0
- 3.3.2
- 3.3.1
- 3.3.0
- 3.2.4
- 3.2.3
- 3.2.2
- 3.2.1
- 3.2.0
- 3.1.3
- 3.1.2
- 3.1.1
- 3.1.0
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 2.x-dev
- 2.3.2
- 2.3.1
- 2.3.0
- 2.2.4
- 2.2.3
- 2.2.2
- 2.2.1
- 2.2.0
- 2.1.4
- 2.1.3
- 2.1.2
- 2.1.1
- 2.1.0
- 2.0.2
- 2.0.1
- 2.0.0
- 2.0.0-BETA
- 1.x-dev
- 1.5.3
- 1.5.2
- 1.5.1
- 1.5.0
- 1.4.0
- 1.3.3
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.2
- 1.2.1
- 1.2.0
- 1.1.0
- 1.0.2
- 1.0.1
- 1.0.0
- 0.1
- dev-fix-ci
- dev-fix-cs
- dev-session-middleware
- dev-custom_reboot_strategy
This package is auto-updated.
Last update: 2026-10-26 12:01:22 UTC
README
RoadRunner is a high-performance PHP application server, load-balancer, and process manager written in Golang.
This bundle provides a RoadRunner Worker integrated in Symfony, it's easily configurable and extendable.
Installation
Run the following command:
composer require baldinof/roadrunner-bundle
If you don't use Symfony Flex:
- register
Baldinof\RoadRunnerBundle\BaldinofRoadRunnerBundlein your kernel - copy default RoadRunner configuration files:
cp vendor/baldinof/roadrunner-bundle/.rr.* .
Usage
- require the RoadRunner download utility:
composer require --dev spiral/roadrunner-cli - get the RoadRunner binary:
vendor/bin/rr get --location bin/ - run RoadRunner with
bin/rr serveorbin/rr serve -c .rr.dev.yaml(watch mode) - visit your app at http://localhost:8080
Integrations
Depending on installed bundle & your configuration, this bundles add some integrations:
- Sentry: configure the request context (if the
SentryBundleis installed) - Sessions: add the session cookie to the Symfony response (if
framework.sessions.enabledconfig istrue) - Doctrine Mongo Bundle: clear opened managers after each requests (if
DoctrineMongoDBBundleis installed) - Doctrine ORM Bundle: clear opened managers and check connection is still usable after each requests (if
DoctrineBundleis installed) - Blackfire: enable the probe when a profile is requested (if the
blackfireextension is installed) - Xdebug: allow Xdebug in trigger mode (if the
xdebugextension is installed)
Even if it is not recommended, you can disable default integrations:
baldinof_road_runner: default_integrations: false
Middlewares
You can use middlewares to manipulate request & responses. Middlewares must implements Baldinof\RoadRunnerBundle\Http\MiddlewareInterface.
Example configuration:
baldinof_road_runner: middlewares: - App\Middleware\YourMiddleware
Be aware that
- middlewares are run outside of Symfony
Kernel::handle() - the middleware stack is always resolved at worker start (can be a performance issue if your middleware initialization takes time)
Raw request body
By default, RoadRunner parses application/x-www-form-urlencoded and multipart/form-data bodies, and $request->getContent() returns a JSON representation of the parsed data instead of the original body.
If you need the original body (e.g. to verify a webhook signature), enable raw_body in RoadRunner:
# .rr.yaml http: raw_body: true
In this mode:
$request->getContent()returns the body as sent by the clientapplication/x-www-form-urlencodedbodies are still parsed by the bundle into$request->requestmultipart/form-databodies are not parsed:$request->requestand$request->filesare empty
Kernel reboots
The Symfony kernel and the dependency injection container are preserved between requests. If an exception is thrown during the request handling, the kernel is rebooted and a fresh container is used.
The goal is to prevent services to be in a non-recoverable state after an error.
To optimize your worker you can allow exceptions that does not put your app in an errored state:
# config/packages/baldinof_road_runner.yaml baldinof_road_runner: kernel_reboot: strategy: on_exception allowed_exceptions: - Symfony\Component\HttpKernel\Exception\HttpExceptionInterface - Symfony\Component\Serializer\Exception\ExceptionInterface - App\Exception\YourDomainException
If some of your services are stateful, you can implement
Symfony\Contracts\Service\ResetInterfaceand your service will be resetted on each request.
If you are seeing issues and want to use a fresh container on each request you can use the always reboot strategy:
# config/packages/baldinof_road_runner.yaml baldinof_road_runner: kernel_reboot: strategy: always
If you are building long-running application and need to reboot it every XXX request to prevent memory leaks you can use max_jobs reboot strategy:
# config/packages/baldinof_road_runner.yaml baldinof_road_runner: kernel_reboot: strategy: max_jobs max_jobs: 1000 # maximum number of request max_jobs_dispersion: 0.2 # dispersion 20% used to prevent simultaneous reboot of all active workers (kernel will rebooted between 800 and 1000 requests)
If you want to reboot the worker when memory usage exceeds a certain threshold to prevent memory exhaustion you can use memory reboot strategy:
# config/packages/baldinof_road_runner.yaml baldinof_road_runner: kernel_reboot: strategy: memory memory_threshold_mb: 256 # memory threshold in megabytes (default: 128MB)
You can combine reboot strategies:
# config/packages/baldinof_road_runner.yaml baldinof_road_runner: kernel_reboot: strategy: [on_exception, max_jobs, memory] allowed_exceptions: - Symfony\Component\HttpKernel\Exception\HttpExceptionInterface - Symfony\Component\Serializer\Exception\ExceptionInterface - App\Exception\YourDomainException max_jobs: 1000 max_jobs_dispersion: 0.2 memory_threshold_mb: 256
Events
The following events are dispatched throughout the worker lifecycle:
Baldinof\RoadRunnerBundle\Event\WorkerStartEvent: Dispatched right before the worker starts listening to requests.Baldinof\RoadRunnerBundle\Event\WorkerStopEvent: Dispatched right before the worker closes.Baldinof\RoadRunnerBundle\Event\WorkerExceptionEvent: Dispatched after encountering an uncaught exception during request handling.Baldinof\RoadRunnerBundle\Event\WorkerKernelRebootedEvent: Dispatched after the symfony kernel was rebooted (see Kernel reboots).
Development mode
Copy the dev config file if it's not present: cp vendor/baldinof/roadrunner-bundle/.rr.dev.yaml .
Start RoadRunner with the dev config file:
bin/rr serve -c .rr.dev.yaml
Reference: https://roadrunner.dev/docs/beep-beep-reload
If you use the Symfony VarDumper, dumps will not be shown in the HTTP Response body. You can view dumps with bin/console server:dump or in the profiler.
Metrics
Roadrunner can collect application metrics, and expose a prometheus endpoint.
Example configuration:
# config/packages/baldinof_road_runner.yaml baldinof_road_runner: metrics: enabled: true collect: user_login: type: counter help: "Number of logged in user"
And configure RoadRunner:
# .rr.yaml rpc: listen: "tcp:127.0.0.1:6001" metrics: address: "0.0.0.0:9180" # prometheus endpoint
Then simply inject Spiral\RoadRunner\MetricsInterface to record metrics:
class YouController { public function index(MetricsInterface $metrics): Response { $metrics->add('user_login', 1); return new Response("..."); } }
gRPC
gRPC support was added by the roadrunner-grpc plugin for RoadRunner 2 (https://github.com/spiral/roadrunner-grpc).
To configure Roadrunner for gRPC, refer to the configuration reference at https://roadrunner.dev/docs/beep-beep-grpc. Basic configuration example:
server: command: "php public/index.php" env: APP_RUNTIME: Baldinof\RoadRunnerBundle\Runtime\Runtime grpc: listen: "tcp://:9001" proto: - "calculator.proto"
Once you have generated your PHP files from proto files, you just have to implement the service interfaces. GRPC services are registered automatically. Example service:
<?php namespace App\Grpc; use Spiral\RoadRunner\GRPC; use App\Grpc\Generated\Calculator\Sum; use App\Grpc\Generated\Calculator\Result; use App\Grpc\Generated\Calculator\CalculatorInterface; class Calculator implements CalculatorInterface { public function Sum(GRPC\ContextInterface $ctx, Sum $in): Result { return (new Result())->setResult($in->getA() + $in->getB()); } }
KV caching
Roadrunner has a KV (Key-Value) plugin that can be used to cache data between requests.
To use it, refer to the configuration reference at https://roadrunner.dev/docs/kv-overview.
This requires the spiral/roadrunner-kv, spiral/goridge and symfony/cache composer dependencies. Basic configuration example:
Example configuration:
# config/packages/baldinof_road_runner.yaml baldinof_road_runner: kv: storages: - example
And configure RoadRunner:
# .rr.yaml rpc: listen: tcp://127.0.0.1:6001 kv: example: driver: memory config: { }
An adapter service will now be created automatically for your storage with the name cache.adapter.roadrunner.kv_<YOUR_STORAGE_NAME>.
Basic usage example:
# config/packages/cache.yaml framework: cache: pools: cache.example: adapter: cache.adapter.roadrunner.kv_example
Usage with Docker
# Dockerfile FROM php:8.1-alpine RUN apk add --no-cache linux-headers autoconf openssl-dev g++ make pcre-dev icu-dev zlib-dev libzip-dev && \ docker-php-ext-install bcmath intl opcache zip sockets && \ apk del --purge autoconf g++ make WORKDIR /usr/src/app COPY --from=composer:latest /usr/bin/composer /usr/bin/composer COPY composer.json composer.lock ./ RUN composer install --no-dev --no-scripts --prefer-dist --no-progress --no-interaction RUN ./vendor/bin/rr get-binary --location /usr/local/bin COPY . . ENV APP_ENV=prod RUN composer dump-autoload --optimize && \ composer check-platform-reqs && \ php bin/console cache:warmup EXPOSE 8080 CMD ["rr", "serve"]