PHPackages                             componenta/app-roadrunner - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. componenta/app-roadrunner

ActiveLibrary[HTTP &amp; Networking](/categories/http)

componenta/app-roadrunner
=========================

RoadRunner HTTP worker runtime for Componenta applications

v1.1.0(today)00MITPHPPHP ^8.4

Since Aug 8Pushed todayCompare

[ Source](https://github.com/componenta/app-roadrunner)[ Packagist](https://packagist.org/packages/componenta/app-roadrunner)[ RSS](/packages/componenta-app-roadrunner/feed)WikiDiscussions master Synced today

READMEChangelog (2)Dependencies (20)Versions (3)Used By (0)

Componenta App RoadRunner
=========================

[](#componenta-app-roadrunner)

`componenta/app-roadrunner` runs Componenta's existing HTTP application pipeline inside a RoadRunner worker. It keeps `Componenta\App\Scope::HTTP`, the normal HTTP bootloaders, middleware configuration, routing, and error handling.

The package owns only the RoadRunner transport lifecycle. Application services that retain request data must expose their own cleanup through `RequestResetterInterface`; this package does not inspect private framework, Cycle, or PHP runtime state.

A Russian guide is available in [README.ru.md](README.ru.md).

Installation
------------

[](#installation)

```
composer config repositories.componenta-app-roadrunner vcs https://github.com/componenta/app-roadrunner.git
composer require componenta/app-roadrunner:dev-dev
composer require --dev spiral/roadrunner-cli:^2.7
vendor/bin/rr get-binary
```

Copy the worker entry point and the example server configuration into the application:

```
cp vendor/componenta/app-roadrunner/resources/bin/roadrunner.php bin/roadrunner.php
cp vendor/componenta/app-roadrunner/resources/.rr.yaml .rr.yaml
```

The Componenta Composer plugin discovers `Componenta\App\RoadRunner\ConfigProvider` from the package metadata. If the application maintains its provider list manually, add this provider after the standard `Componenta\App\Server\ConfigProvider`.

Rebuild Componenta's production cache after installing the package or changing its configuration:

```
php bin/console.php app:build
```

Build and publish caches before starting or reloading the worker pool. Workers must only read completed shared artifacts; they must not race to generate config, container, discovery, route, DI, or ORM caches during concurrent boot. Restart all workers after a cache or code deployment so no long-lived container keeps the previous release.

Start the server:

```
./rr serve -c .rr.yaml
```

Runtime selection
-----------------

[](#runtime-selection)

`Componenta\App\RoadRunner\AppFactory` replaces the default concrete app factory while keeping Componenta's public `AppFactoryInterface`. It selects the RoadRunner app only when RoadRunner sets `RR_MODE=http`. Outside a RoadRunner worker it delegates to Componenta's default factory, so the existing FPM, SAPI, and CLI entry points keep the same behavior. The RoadRunner app implements `HttpBootTargetInterface` directly, and the standard `componenta/app-http`adapter uses it without an integration-specific adapter.

There is no separate RoadRunner scope and no manual `always` mode. Starting the RoadRunner app without the RoadRunner worker protocol would be invalid, while forcing the SAPI app inside a worker would corrupt that protocol.

Request lifecycle
-----------------

[](#request-lifecycle)

The RoadRunner app:

1. builds the configured PSR-15 middleware pipeline once;
2. refreshes RoadRunner's `$_SERVER` baseline after Componenta boot completes;
3. receives PSR-7 requests through the official `PSR7Worker`;
4. handles every request through the same Componenta pipeline;
5. prepares and sends the PSR-7 response;
6. runs configured request resetters in declaration order;
7. clears output buffers opened by the request;
8. accepts the next request.

Middleware priority and equal-priority registration order match `componenta/app-http`.

An unhandled pipeline exception becomes an empty generic `500` response. Invalid RoadRunner request data becomes an empty generic `400`. A transport or cleanup failure exits the worker with code `1`, allowing RoadRunner to replace a process whose state is no longer trusted.

Request state
-------------

[](#request-state)

The package automatically clears Componenta's `CurrentUserProviderInterface` after application resetters run. Other mutable shared services must register an explicit resetter:

```
namespace App\Infrastructure\Reset;

use App\Tenant\TenantContext;
use Componenta\App\RoadRunner\Reset\RequestResetterInterface;

final readonly class TenantContextResetter implements RequestResetterInterface
{
    public function __construct(private TenantContext $context) {}

    public function reset(): void
    {
        $this->context->clear();
    }
}
```

Register its service id in execution order:

```
return [
    'roadrunner' => [
        'resetters' => [
            App\Infrastructure\Reset\TenantContextResetter::class,
        ],
    ],
];
```

All resetters are attempted even if one fails. Failures are aggregated into `ResetFailedException`, and the worker exits after cleanup.

Cycle transactions, `EntityManager`, ORM heap, tenant context, locale, profiler state, and similar mutable services belong to their owning integration. Register resetters for the services used by the application. Do not store request objects or users in static properties or long-lived controller properties. Keep RoadRunner's `max_jobs` limit as a final guard against third-party leaks and memory fragmentation.

Configuration
-------------

[](#configuration)

```
return [
    'roadrunner' => [
        'http' => [
            'chunk_size' => 0,
        ],
        'worker' => [
            'intercept_side_effects' => true,
        ],
        'resetters' => [],
    ],
];
```

- `roadrunner.http.chunk_size` controls RoadRunner's streamed PSR-7 response mode. The default `0` lets the official worker materialize the body and also supports non-seekable PSR-7 streams. A positive value requires rewindable response bodies.
- `roadrunner.worker.intercept_side_effects` protects the Goridge protocol from accidental PHP output to stdout.
- `roadrunner.resetters` is an ordered list of container service ids implementing `RequestResetterInterface`.

A copyable configuration file is included at `resources/config/autoload/roadrunner.global.php`.

Response transport
------------------

[](#response-transport)

`ResponsePreparer` preserves the observable HTTP response semantics for `HEAD`, informational and bodyless statuses, full responses, `206 Content-Range`, non-seekable streams, `X-Sendfile`, and `X-Accel-Redirect`. It performs RoadRunner-specific transport normalization before the response crosses Goridge, so internal PSR-7 headers and body objects are not guaranteed to be identical to those passed to Componenta's SAPI emitter.

To use `X-Sendfile`, enable RoadRunner's sendfile middleware:

```
http:
  middleware: ["sendfile"]
```

Public API
----------

[](#public-api)

- `ConfigProvider` wires the integration into Componenta's application factory.
- `App` is the long-running HTTP application and also its HTTP boot target.
- `RequestResetterInterface` is the application cleanup extension point.
- `ResetFailedException` exposes all cleanup failures through its `failures`property.

The worker loop and factory are container-managed infrastructure; application code normally interacts only with `RequestResetterInterface`.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

2

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/20490712?v=4)[Andrey Shelamkoff](/maintainers/Shelamkoff)[@Shelamkoff](https://github.com/Shelamkoff)

---

Top Contributors

[![Shelamkoff](https://avatars.githubusercontent.com/u/20490712?v=4)](https://github.com/Shelamkoff "Shelamkoff (8 commits)")

---

Tags

psr-7psr-15roadrunnerlong-runningapplication-servercomponenta

###  Code Quality

TestsPest

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/componenta-app-roadrunner/health.svg)

```
[![Health](https://phpackages.com/badges/componenta-app-roadrunner/health.svg)](https://phpackages.com/packages/componenta-app-roadrunner)
```

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.9k20.0M1.8k](/packages/cakephp-cakephp)[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

7.9k1.1B4.4k](/packages/guzzlehttp-psr7)[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k19](/packages/tempest-framework)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[sunrise/http-router

A powerful solution as the foundation of your project.

17452.3k12](/packages/sunrise-http-router)[mezzio/mezzio

PSR-15 Middleware Microframework

3973.9M132](/packages/mezzio-mezzio)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
