PSR-7 HTTP worker for the RoadRunner application server
RoadRunner HTTP is the PHP side of the RoadRunner HTTP plugin. It turns requests served by RoadRunner into PSR-7 objects and sends PSR-7 responses back, including streamed responses and HTTP 103 Early Hints.
composer require spiral/roadrunner-httpThe worker needs a PSR-17 implementation, for example
nyholm/psr7, which is used in the examples below:
composer require nyholm/psr7The RoadRunner binary can be downloaded with the RoadRunner CLI:
composer require spiral/roadrunner-cli --dev
vendor/bin/rr getEnsure that your server is configured with the following PHP versions and extensions:
- PHP >=8.2
- ext-protobuf: This extension is optional but highly recommended for installation. Without it, performance may be up to 50% lower.
- RoadRunner ^3.0
Enable the http plugin in .rr.yaml and point the server at your worker script:
version: "3"
server:
command: "php worker.php"
http:
address: "0.0.0.0:8080"All available options are described in the plugin documentation.
A worker.php that answers every request:
<?php
require __DIR__ . '/vendor/autoload.php';
use Nyholm\Psr7\Response;
use Nyholm\Psr7\Factory\Psr17Factory;
use Spiral\RoadRunner\Worker;
use Spiral\RoadRunner\Http\PSR7Worker;
// Create new RoadRunner worker from global environment
$worker = Worker::create();
// Create common PSR-17 HTTP factory
$factory = new Psr17Factory();
//
// Create PSR-7 worker and pass:
// - RoadRunner worker
// - PSR-17 ServerRequestFactory
// - PSR-17 StreamFactory
// - PSR-17 UploadFilesFactory
//
$psr7 = new PSR7Worker($worker, $factory, $factory, $factory);
while (true) {
try {
$request = $psr7->waitRequest();
} catch (\Throwable $e) {
// Although the PSR-17 specification clearly states that there can be
// no exceptions when creating a request, however, some implementations
// may violate this rule. Therefore, it is recommended to process the
// incoming request for errors.
//
// Send "Bad Request" response.
$psr7->respond(new Response(400));
continue;
}
// The worker has been asked to stop
if ($request === null) {
break;
}
try {
// Here is where the call to your application code will be located.
// For example:
//
// $response = $app->send($request);
//
// Reply by the 200 OK response
$psr7->respond(new Response(200, [], 'Hello RoadRunner!'));
} catch (\Throwable $e) {
// In case of any exceptions in the application code, you should handle
// them and inform the client about the presence of a server error.
//
// Reply by the 500 Internal Server Error response
$psr7->respond(new Response(500, [], 'Something Went Wrong!'));
// Additionally, we can inform the RoadRunner that the processing
// of the request failed.
$worker->error((string)$e);
}
}Start the server with ./rr serve.
To send a response in a stream, set the $chunkSize property in PSR7Worker:
$psr7 = new PSR7Worker($worker, $factory, $factory, $factory);
$psr7->chunkSize = 512 * 1024; // 512KBNow PSR7Worker will cut the response into chunks of 512KB and send them to the stream.
To send multiple responses you may use the \Spiral\RoadRunner\Http\HttpWorker::respond() method with
the endOfStream parameter set to false. This will send the response to the client and allow you to send
additional responses.
/** @var \Spiral\RoadRunner\Http\PSR7Worker $psr7 */
$psr7->getHttpWorker()
->respond(103, headers: ['Link' => ['</style.css>; rel=preload; as=style']], endOfStream: false);
// End of stream will be sent automatically after PSR7Worker::respond() call
$psr7->respond(new Response(200, [], 'Hello RoadRunner!'));composer test