Profiling ReactPhp HTTP Server requests

By Romain Neutron, on Oct 09, 2015

Using Blackfire within an evented webserver such as React PHP HTTP Server is possible; let’s have a look at it.

We’ve had quite a few support requests about how to profile PHP webserver such as React or Swoole. Those web servers handle requests in a totally different way than traditional web servers. PHP scripts are loaded when a request starts, and unloaded once the request is finished. React or Swoole are long running scripts that never stop and trigger an event when an HTTP request comes in.
These servers usually rely on event loops to accomplish their jobs.

Here’s a simple React webserver:

use React\EventLoop\Factory as LoopFactory;
use React\Socket\Server as SocketServer;
use React\Http\Server as HttpServer;

$loop = LoopFactory::create();
$socket = new SocketServer($loop);

$http = new HttpServer($socket);

$http->on('request', function ($request, $response) {
    $response->writeHead(200, ['Content-Type' => 'text/plain']);
    $response->end("Hello World!\n");
});

$socket->listen(1337);
$loop->run();

Profiling such an application is quite easy with Blackfire, all you have to do is to manually enable the Probe at the beginning of the request, add the appropriate HTTP header to the response, and disable the Probe once the request is sent.

Using the Blackfire\ReactHttpServer::handle method from Blackfire PHP SDK eases the workflow:

include __DIR__.'/vendor/autoload.php';

use React\EventLoop\Factory as LoopFactory;
use React\Socket\Server as SocketServer;
use React\Http\Server as HttpServer;
use Blackfire\Bridge\ReactHttpServer as BlackfireHandler;

$loop = LoopFactory::create();
$socket = new SocketServer($loop);
$blackfire = new BlackfireHandler();

$http = new HttpServer($socket);
$http->on('request', function ($request, $response) use ($blackfire) {
    $headers = array_merge(['Content-Type' => 'text/plain'], $blackfire->handle($request, $response));

    $response->writeHead(200, $headers);
    $response->end("Hello World!\n");
});

$socket->listen(1337);
$loop->run();

This works well. However, you should be very careful when profiling an event-based script because the web server can handle requests concurrently. This means the result may contain data which is not related to the request that triggered the profile.

So you should probably only use this in a development environment.

Happy profiling!

Romain Neutron

Romain is a developer at Blackfire.io. He started programming years ago while he was studying physics. He loved it so much he stopped his studies to be a programmer and contributed to various open source projects. He joined SensioLabs in 2014 to work on Blackfire and discovered a new love in application performance.