fluffydiscord / rapira-symfony-bundle
Rapira runtime for Symfony
Package info
github.com/FluffyDiscord/rapira-symfony-bundle
Type:symfony-bundle
pkg:composer/fluffydiscord/rapira-symfony-bundle
Requires
- php: >=8.4
- psr/log: ^3
- rapira/contract: dev-master
- symfony/dependency-injection: ^7.4 || ^8
- symfony/error-handler: ^7.4 || ^8
- symfony/event-dispatcher: ^7.4 || ^8
- symfony/framework-bundle: ^7.4 || ^8
- symfony/http-foundation: ^7.4 || ^8
- symfony/http-kernel: ^7.4 || ^8
Requires (Dev)
- doctrine/dbal: ^3 || ^4
- doctrine/orm: ^2 || ^3
- doctrine/persistence: ^3 || ^4
- jcupitt/vips: ^2
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2
- phpstan/phpstan-symfony: ^2
- phpunit/phpunit: ^13
- sentry/sentry-symfony: ^5
- symfony/form: ^7.4 || ^8
- symfony/mime: ^7.4 || ^8
Suggests
- ext-xhprof: Per-request profiling under the resident worker
- doctrine/dbal: Preconnect Doctrine connections at worker boot
- jcupitt/vips: Bound libvips's process-global cache at worker boot (RSS control)
- sentry/sentry-symfony: Report worker exceptions to Sentry
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-09-05 18:11:23 UTC
README
Run a Symfony app as a resident worker under Rapira, classic or dispatcher mode.
HTTP worker only. No Jobs / KV / Centrifugo / Temporal (waiting for Rapira).
Requirements
- PHP >= 8.4
- Rapira pool with
mode = "dispatcher"for the resident worker (classic mode uses the standard runtime) symfony/*^7.4 || ^8
Installation
composer require fluffydiscord/rapira-symfony-bundle
Register the bundle (config/bundles.php):
FluffyDiscord\RapiraBundle\FluffyDiscordRapiraBundle::class => ['all' => true],
Add the kernel trait (src/Kernel.php) so a rebooted kernel keeps the properties the worker preserves:
use FluffyDiscord\RapiraBundle\Kernel\RapiraMicroKernelTrait; class Kernel extends BaseKernel { use RapiraMicroKernelTrait; }
worker.php ships vendored — nothing to write. It boots .env with usePutenv() (no symfony/runtime) and hands the kernel to the worker. public/index.php and bin/console stay as the skeleton ships them (classic mode + console).
Copy the sample rapira.toml to the project root (Rapira reads it from there) and edit your copy:
cp vendor/fluffydiscord/rapira-symfony-bundle/rapira.toml rapira.toml
[http] listen = "0.0.0.0:8000" max_body_size_mb = 20 [http.uploads] dir = "/tmp" max_file_size_mb = 1 max_files = 20 [pool] entrypoint = "vendor/fluffydiscord/rapira-symfony-bundle/worker.php" mode = "dispatcher" processes = 4 [log] level = "info" format = "json"
Keep entrypoint pointing at the vendored worker.php; change everything else freely. Kernel class defaults to App\Kernel; override with APP_KERNEL_CLASS.
dev → classic, prod → dispatcher. Classic runs the standard runtime per request (rapira serve --classic public/index.php), so code changes are picked up with no worker restart. Dispatcher runs the resident worker (worker.php). The console always uses the standard runtime (php bin/console).
Configuration
# config/packages/rapira.yaml rapira: warmup: enabled: true # boot-time warmers + learned-manifest recorder learn: true learn_requests: 30 # stop recording after N responses per worker manifest_path: ~ # default: %kernel.cache_dir%/rapira/warmup.manifest.json doctrine: preconnect: true # open Postgres connections at worker boot profiling: xhprof: enabled: false # false (default) | true | "auto" (ext-xhprof loaded and kernel.debug) output_dir: ~ # default: ini xhprof.output_dir, then sys_get_temp_dir()/xhprof vips: # bound libvips's process-global cache at worker boot enabled: auto # auto - true if jcupitt/vips installed max_operations: 50 max_memory_mb: 50 max_files: 20
Dispatcher-mode notes
- Streaming.
StreamedResponse/StreamedJsonResponsestream progressively, carryX-Accel-Buffering: no. Callbacks mustecho(orsetChunks()); ayield-based callback is not run bysendContent(). - Superglobals empty. Read from the injected
Request, not$_GET/$_SERVER.echo/header()output is discarded — respond through the Response. - Logging.
error_log()is discarded; the bundle logs via\Rapira\log()(theapptarget). - Sessions work unchanged (native or
PdoSessionHandler);services_resetterclears per-request state. - Uploads are parsed host-side (
[http.uploads]), mapped to SymfonyUploadedFiles.move()renames the host temp file before the exchange finalizes.
Events
WorkerBootingEvent, WorkerRequestReceivedEvent (Rapira\Http\Request), WorkerResponseSentEvent (Symfony request + response), WorkerRequestFailedEvent (Rapira\Http\Request + throwable).
Testing
tests/docker-qa.sh # PHPStan (level max) + PHPUnit, in a container tests/docker/run-integration.sh # IT-101..IT-107 against the real Rapira binary