upscale/swoole-blackfire
Integrates Blackfire profiling with Swoole workers, enabling per-request profiling in long-running Laravel Octane applications. Helps Blackfire traces work correctly across persistent PHP workers instead of only the initial request.
composer require --dev upscale/swoole-blackfire. You don't want this in production images.swoole extension loaded (php -m | grep swoole).php -m | grep blackfire), not just the blackfire CLI/agent.127.0.0.1:8307) and BLACKFIRE_SERVER_ID / BLACKFIRE_SERVER_TOKEN (or client id/token) in the environment. The agent, not the package, is what accepts the profile.src/ first. The entry point is an invokable Profiler in the Upscale\Swoole\Blackfire namespace that wraps a Swoole onRequest handler. The README's minimal example is roughly:use Swoole\Http\Server;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Upscale\Swoole\Blackfire\Profiler;
$server = new Server('0.0.0.0', 8080);
$server->on('request', new Profiler(function (Request $req, Response $res) {
$res->end('ok');
}));
$server->start();
RINIT/RSHUTDOWN, the probe extension will not auto-start on the X-Blackfire-Query header the way it does under FPM — the package exists specifically to bridge that gap by enabling/disabling the probe manually around each request.Profiler as the outermost onRequest handler. Everything you want in the profile (routing, Laravel/Octane dispatch, DB I/O, rendering) must happen inside the wrapped closure.blackfire_probe_enable() when the incoming request actually carries a Blackfire query header. On every other request it should be effectively a no-op — verify this by load-testing with the header absent.GET /orders/{id} over /orders/12345.blackfire_span_start('db:users') / blackfire_span_stop() inside the handler to mark sub-operations; those show up alongside the automatic function calls.Server::task() or a timer are outside the onRequest wrapper. Don't expect a profile from them; instrument them by hand or use the standard blackfire run CLI integration in a separate process to avoid colliding with the HTTP probe.blackfire_probe_enable(): probe is already enabled. Wrap the handler in try { ... } finally { /* stop */ }, or file a patch/vendor the package if its stop path isn't exception-safe.$request->header, while Blackfire tooling and proxies may send X-Blackfire-Query. If profiling silently never triggers, var_dump($request->header) to confirm the key the wrapper is looking for.php.ini requires a full worker restart; reload may not pick it up. In dev, restart the Swoole master process.require-dev, gate instantiation behind an env check (APP_ENV=local), and don't ship the Blackfire token in images that run outside your local machine.X-Blackfire-Query value intact end-to-end.^1.0) and be ready to vendor or fork if the API doesn't match your Swoole version. Read the source — it's small enough to audit in a few minutes, and that's the fastest way to learn its actual extension points (constructor arguments, name resolver, stop behavior).blackfire agent:status) and the BLACKFIRE_LOG_LEVEL setting before assuming a package bug.How can I help you explore Laravel packages today?