Этот документ описывает фактический runtime flow HTTP-запроса.
Client
-> RoadRunner HTTP
-> public/index.php
-> App
-> DI container
-> Pipeline
-> Middleware chain
-> Router
-> Handler
-> Mapper / JsonResponse
-> Response
RoadRunner запускает PHP worker через:
server:
command: "php public/index.php"Файл public/index.php создаёт App и вызывает run().
src/Platform/Runtime/App.php делает следующее:
- загружает
config/container.php; - создаёт
DIContainer; - регистрирует сервисы через service providers;
- получает
PSR7Worker; - собирает middleware pipeline из platform middleware и capability middleware.
Кеш при старте worker-а больше не очищается глобально.
Deployment-aware invalidation теперь идёт через namespace_seed в cache config, а runtime invalidation внутри приложения должна опираться на namespace/scope rotation, а не на полный wipe shared backend-а.
Внутри App::run() работает бесконечный цикл:
waitRequest()handleRequest($request)respond($response)
Это long-running модель, поэтому любой singleton-like объект живёт дольше одного запроса.
Pipeline в проекте рекурсивный. Каждый middleware получает:
- текущий
ServerRequestInterface; - следующий
RequestHandler.
Порядок выполнения:
RequestContextMiddlewareErrorHandlerMiddlewareSessionMiddlewareApiStatsMiddlewareRoutingMiddlewareHttpLoggingMiddleware- конечный
RouteHandlerResolver
RequestContextMiddleware создаёт общий request-scoped context:
requestId- inherited
Deadline
Если клиент уже прислал X-Request-ID, runtime сохраняет его. Иначе request ID генерируется внутри Platform/Runtime/RequestContextFactory.
Этот context живёт в request attributes и должен считаться канонической точкой привязки для downstream timeout-budget propagation.
Это ключевой этап, потому что он формирует session context поверх уже существующего request context.
Основные действия:
- ищет session ID в
Authorization: Bearer ...или cookie; - валидирует существующую сессию;
- если сессии нет, формирует
SessionPayload; - при необходимости создаёт новую анонимную сессию;
- для небраузерных клиентов может попытаться восстановить сессию по fingerprint;
- добавляет объект
sessionв request attributes; - после успешного ответа refresh-ит TTL и выставляет
Set-Cookie.
В результате downstream код может считать, что:
requestContextуже присутствует в request;sessionуже присутствует в request.
Измеряет время выполнения запроса и сохраняет запись в api_stats.
Что он использует:
sessionиз request attributes;- route information после dispatch;
- HTTP method, status code, execution time.
Это cross-cutting concern, но он зависит от фактической модели сессий.
Вызывает router и определяет:
- найден ли маршрут;
- какой handler должен выполнить запрос;
- какие route params надо записать в request.
Если маршрут не найден, middleware сразу возвращает JSON error response.
Если маршрут найден, в request attributes кладутся:
routeParamshandler
Финальный request handler в pipeline.
Его задача:
- взять имя handler из request attributes;
- разрешить handler через DI;
- вызвать
handle($request).
Таким образом, middleware не знает, как именно создаётся handler, а runtime resolution централизован.
На примере HealthService.Check flow выглядит так:
- router выбирает сгенерированный
CheckHttpHandler; - handler декодирует protobuf request через
AbstractProtobufRpcHandler; - handler вызывает handwritten endpoint implementation
App\Platform\Http\Endpoint\Api\V1\HealthService\CheckEndpoint; - endpoint implementation создаёт protobuf response model;
- handler отдаёт JSON через
JsonResponse.
Именно здесь reusable transport adapter должен заканчиваться, а прикладная логика начинаться в endpoint implementation.
Response возвращается обратно через цепочку middleware.
На обратном пути возможны побочные эффекты:
SessionMiddlewarerefresh-ит сессию и выставляет cookie;ApiStatsMiddlewareсохраняет метрику;HttpLoggingMiddlewareпишет лог;ErrorHandlerMiddlewareперехватывает исключения и нормализует ошибку.
- Сессия создаётся до routing и handler.
- Route selection происходит не по контроллерам, а по сгенерированному route config.
- Default runtime не должен зависеть от demo-flow кода.
- Long-running runtime требует осторожности с кешами, статикой и состоянием сервисов.