baldinof / roadrunner-bundle
A RoadRunner worker as a Symfony Bundle
Fund package maintenance!
Baldinof
Installs: 825 629
Dependents: 1
Suggesters: 0
Security: 0
Stars: 271
Watchers: 5
Forks: 48
Open Issues: 28
Type:symfony-bundle
Requires
- php: >=8.1
- psr/log: ^1.1 || ^2.0 || ^3.0
- spiral/goridge: ^4.0
- spiral/roadrunner: ^2023.1.0 || ^2024.1.0
- spiral/roadrunner-http: ^3.0
- spiral/roadrunner-worker: ^3.0.0
- symfony/config: ^6.0 || ^7.0
- symfony/dependency-injection: ^6.0 || ^7.0
- symfony/http-kernel: ^6.0 || ^7.0
- symfony/yaml: ^6.0 || ^7.0
Requires (Dev)
- blackfire/php-sdk: ^1.21
- doctrine/doctrine-bundle: ^2.1.1
- doctrine/mongodb-odm: ^2.2
- doctrine/orm: ^2.7.3
- laminas/laminas-zendframework-bridge: ^1.4
- mikey179/vfsstream: ^1.6.8
- nyholm/psr7: ^1.2
- sentry/sentry-symfony: ^4.5 || ^5.0
- spiral/roadrunner-grpc: ^3.0.0
- spiral/roadrunner-kv: ^4.0
- spiral/roadrunner-metrics: ^3.0.0
- symfony/framework-bundle: ^6.0 || ^7.0
- symfony/proxy-manager-bridge: ^6.0 || ^7.0
- symfony/runtime: ^6.0 || ^7.0
- symfony/validator: ^6.0 || ^7.0
- symfony/var-dumper: ^6.0 || ^7.0
- symfony/var-exporter: ^6.0 || ^7.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
Conflicts
- doctrine/doctrine-bundle: <2.1.1
- sentry/sentry-symfony: <4.5.0
- spiral/roadrunner-metrics: <3.0.0
- 3.x-dev
- 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-session-middleware
- dev-custom_reboot_strategy
This package is auto-updated.
Last update: 2024-12-06 11:26:10 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\BaldinofRoadRunnerBundle
in 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 serve
orbin/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
SentryBundle
is installed) - Sessions: add the session cookie to the Symfony response (if
framework.sessions.enabled
config istrue
) - Doctrine Mongo Bundle: clear opened managers after each requests (if
DoctrineMongoDBBundle
is installed) - Doctrine ORM Bundle: clear opened managers and check connection is still usable after each requests (if
DoctrineBundle
is installed) - Blackfire: enable the probe when a profile is requested (if the
blackfire
extension 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)
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\ResetInterface
and 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)
You can combine reboot strategies:
# config/packages/baldinof_road_runner.yaml baldinof_road_runner: kernel_reboot: strategy: [on_exception, max_jobs] allowed_exceptions: - Symfony\Component\HttpKernel\Exception\HttpExceptionInterface - Symfony\Component\Serializer\Exception\ExceptionInterface - App\Exception\YourDomainException max_jobs: 1000 max_jobs_dispersion: 0.2
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"]