Laravel Octane: Supercharge Performance with Swoole

· 4 min read

Traditional PHP application lifecycle boots the framework for every incoming request. This means loading configuration, service providers, and database connections repeatedly.

Laravel Octane changes this by keeping your application in memory, allowing for blazing fast response times.

How Octane Works

Octane serves your application using high-performance application servers like Swoole or RoadRunner. It boots your application once, keeps it in memory, and feeds it requests at incredible speeds.

Installation

Install via Composer:

composer require laravel/octane

Install Swoole (via PECL) or RoadRunner. For this guide, we'll assume Swoole:

php artisan octane:install --server=swoole

This publishes the config/octane.php file.

Starting the Server

php artisan octane:start

Your app is now running at http://127.0.0.1:8000. You should feel the speed immediately.

Handling Stateful Logic

Because the application is kept in memory, you must be careful with state.

Dependency Injection (Singletons)

In a standard request lifecycle, a singleton is destroyed after the request. In Octane, a singleton persists across requests.

Problem:

// AppServiceProvider
$this->app->singleton(Service::class, function () {
    return new Service(request()); // Creates service with FIRST request
});

Subsequent requests will reuse this service instance with the OLD request data.

Solution:

Inject the container, or pass the request into the method call, not the constructor.

$this->app->bind(Service::class, function ($app) {
    return new Service($app['request']);
});

Static Properties

Static properties persist between requests.

Problem:

class UserContext {
    public static $userId;
}

// Request 1 sets ID 5
UserContext::$userId = 5;

// Request 2 (different user) reads ID 5!

Solution:

Avoid static properties for request-scope state. Or, reset them using Octane's listeners.

Managing Memory Leaks

Octane automatically handles some cleanup, but you can configure it to restart after a certain number of requests or memory usage.

php artisan octane:start --max-requests=1000

This prevents slow memory leaks from consuming all server resources over time.

Concurrent Tasks with Swoole

One of the coolest features of Octane (with Swoole) is concurrent execution.

use Laravel\Octane\Facades\Octane;

[$users, $posts] = Octane::concurrently([
    fn () => User::all(),
    fn () => Post::all(),
]);

These database queries run in parallel, significantly reducing total response time.

Evaluation & Tables (Swoole Only)

Octane tables allow high-performance data sharing between concurrent workers.

use Laravel\Octane\Facades\Octane;
use Swoole\Table;

// Configuration
Octane::table('cache', [
    'value' => [
        'type' => Table::TYPE_STRING,
        'size' => 1000,
    ],
]);

// Usage
Octane::table('cache')->set('key', ['value' => 'stored_data']);

Cache Driver

Octane provides an in-memory cache driver powered by Swoole tables. It offers microsecond-level read/write speeds.

Cache::store('octane')->put('framework', 'Laravel', 30);

Route Caching

Since the app is booted once, route caching is less critical for boot time but still important for dispatch speed.

php artisan route:cache

Production Deployment

For production, you typically run Octane behind a reverse proxy like Nginx.

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

server {
    listen 80;
    server_name example.com;
    root /path/to/public;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}

Use Supervisor to keep the Octane process running.

[program:octane]
command=php /path/to/artisan octane:start --server=swoole --max-requests=1000
autostart=true
autorestart=true
user=www-data
redirect_stderr=true
stdout_logfile=/path/to/octane.log

Best Practices checklist

  1. Avoid Global State: Be wary of static properties.
  2. Request Injection: Don't inject Request into Singleton constructors.
  3. Memory Management: Monitor memory usage and set max-requests.
  4. Listeners: Use Octane::tick() or listeners to reset state if necessary.
  5. Concurrency: Use Octane::concurrently for independent heavy operations.

Summary

Laravel Octane enables PHP to compete with Node.js and Go in terms of raw throughput. While it introduces some complexity regarding state management, the performance gains for high-traffic applications are undeniable.

Comments