I Can’t Wait for Laravel Octane

Roberto Butti
Geek Culture
Published in
5 min readMar 29, 2021

I can’t wait for Laravel Octane, so I started playing with Laravel and Roadrunner.

On 6th April 2021, Laravel Octane Beta is released, so this article is obsolete. My suggestion is to use Laravel Octane with Roadrunner. To do that, you can follow this post: https://robertodev.medium.com/laravel-octane-is-here-9ce026f6180e

During Laracon 2021 🎉🎉🎉, and after Taylor’s great “Laravel Octane” speech, I was super excited about serving Laravel application with an Application Server with multiple workers.

Under the hood Laravel Octane could be used with Roadrunner, so I decided to play a little bit directly with Roadrunner.

What is Roadrunner: Roadrunner is an Application Server written in Go, for serving PHP application.

Install

What we are going to do:

  • install a new Laravel application from scratch
  • install a HTTP Benchmarking tool
  • install Roadrunner
  • install Laravel “bridge” for using Roadrunner with Laravel framework
  • configure Roadrunner
  • start the Application Server
  • execute a comparison benchmark with Nginx and Roadrunner
  • show some consideration, because using an Application Server is different when you use a Web Server.

Install new Laravel application from scratch

I’m going to create a new Laravel application from scratch.

So first of all, I need to install or update “laravel” tool. It is useful for creating a new Laravel application:

composer global require laravel/installer

Then i can create the new Laravel application:

laravel new laravel-turbo
cd laravel-turbo

I suggest to create this application in the directory served by Valet. So you can reach this through your Browser via Nginx : http://laravel-turbo.test

Install the HTTP Benchmarking Tool

In order to retrieve some insight about the performance and mimic a lot of concurrent traffic on your Laravel App, I’m going to use “Wrkhttps://github.com/wg/wrk.

If you have a macOS and you are using Homebrew , you can install “Wrk”:

brew install wrk

With Wrk you can generate many simultaneous requests for a defined period of time. Later I will use it to run some benchmarks. Before that, let me install the application server and its bridge for Laravel.

Install Roadrunner

Now I’m going to install the Application Server, later I will install the Laravel bridge.

The GitHub repository of the Application Server is: https://github.com/spiral/roadrunner-binary

To install Roadrunner, you need:

  • install the PHP package of the Application Server;
  • get the binary (executable files) of the application server;
  • make sure that rr binary is executable (executable permission);
  • configure the application server via .rr.yaml file.
composer require spiral/roadrunner:v2.0 nyholm/psr7
./vendor/bin/rr get-binary
chmod u+x rr

Install Roadrunner Laravel Bridge

For Laravel to work properly with the Application Server, you need to install Roadrunner Laravel Bridge and then publish the configuration file for Laravel Bridge:

composer require spiral/roadrunner-laravel "^4.0"
php artisan vendor:publish --provider='Spiral\RoadRunnerLaravel\ServiceProvider' --tag=config

Configure Roardrunner

The configuration for the Application Server is in the file .rr.yaml.

A basic configuration for our example could be something like:

server:
# If you want to use Unix socket for internal communication:
#command: "php ./vendor/bin/rr-worker start --relay-dsn unix://rr-laravel-rpc.sock"
#relay: "unix://rr-laravel-rpc.sock"
# If you want to use TCP socket for internal communication:
command: "php ./vendor/bin/rr-worker start --relay-dsn tcp://127.0.0.1:7001"
relay: "tcp://127.0.0.1:7001"

http:
# The Web application is served via 8080 port
address: 0.0.0.0:8080
middleware: ["headers", "static", "gzip"]
pool:
num_workers: 4
max_jobs: 64
supervisor:
exec_ttl: 60s
headers:
response:
X-Powered-By: "RoadRunner"
static:
dir: "public"
forbid: [".php"]

Start the Application Server

Start the application server with new “rr” executable just downloaded:

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

Once the Application Server is started, according to the configuration (num_workers) 4 workers are started, ready to serve the Laravel application.

According to the “address” parameter in configuration file, the Laravel application is exposed on 8080 port.

Execute test comparison, Nginx VS Roadrunner

For executing tests, I’m going to use “wrk” to generate traffic and 2 different URL, each URL is referring two different service:

I’m going to use some specific option:

  • 4 threads to use;
  • 20 connections to keep open;
  • 10 secondo of duration of test.

So for testing Nginx:

wrk -t4 -c20 -d10s http://laravel-turbo.test

For testing Roadrunner:

wrk -t4 -c20 -d10s http://laravel-turbo.test:8080

The result are different.

For Nginx I had 478 requests in ten seconds:

4 threads, 20 connections keep open, to Nginx

For Roardrunner I had 1728 requests in ten seconds

The difference is impressive. Roadrunner is much faster than Nginx.

Some considerations

The main difference with serving the Laravel application with Roadrunner instead of the classic Web server is:

  • The Application is bootstrapped once, and multiple request will share same resources.
  • The construct of the controller are called once (when the worker is instanced)
  • Think what happens to “static” class attribute

Let me explain an example.

Create 2 routes in routes/web.php:

use App\Http\Controllers\MainController;Route::get('/', [MainController::class, 'index']);Route::get('/show', [MainController::class, 'show']);

Create MainController.php in app/Http/Controllers directory where you:

  • define a static attribute (array) $list;
  • define index method where you append a random integer to the self::$list array;
  • define show method where you use and show the self::$list array
<?phpnamespace App\Http\Controllers;use Illuminate\Http\Request;class MainController extends Controller{  public static $list = [];  public function index()  {    self::$list[]= \random_int(1,6);    return view('welcome');  }  public function show()  {    return view('show', ["list" => self::$list]);  }}

If you call multiple time http://laravel-turbo.test:8080/ it will be called index method so some integer will be added to your list. The static list is shared across the request on the same worker. So if you try to call http://laravel-turbo.test:8080/show it will be called show method where list attribute will be used.

So I think that working in an Application Server context for a PHP developer is a great changes specially thinking about the life cycle of the request. A PHP developer typically is used to have all the Framework instanced in every request.

Probably Laravel Octane will be responsible to expose to Laravel a clean state for each request making the life easier for PHP developers.

Do you agree with those considerations?

Feel free to drop some comments and/or feedbacks.

--

--

Roberto Butti
Geek Culture

I’m technophile. Vuejs and Laravel enthusiast! #vuejs #laravel. I love #coding