Cos’è Octane
Laravel Octane è un pacchetto che migliora drasticamente le prestazioni di Laravel usando application server ad alte prestazioni.
Con PHP-FPM l’app parte e termina a ogni richiesta. Con Octane l’app parte una volta e resta in memoria: le richieste successive sono molto più veloci.
La differenza principale con PHP-FPM: il bootstrap (service provider, ecc.) non si ripete per ogni richiesta.
Server supportati
| Server | Linguaggio | Installazione | Task concorrenti | Note |
|---|
| FrankenPHP | Go | Automatica | — | Consigliato. HTTP/3, Brotli |
| RoadRunner | Go | Automatica | — | Semplice |
| Swoole | Estensione PHP | Manuale via PECL | ✅ | Task concorrenti, Octane cache |
Laravel Cloud offre Octane con FrankenPHP completamente gestito.
Installazione
composer require laravel/octane
php artisan octane:install
Il prompt ti fa scegliere il server; viene creato config/octane.php.
FrankenPHP / RoadRunner
Octane scarica il binario. Nessun passo aggiuntivo.
Swoole
Per Open Swoole:
Avvio
Porta di default 8000.
php artisan octane:start --server=frankenphp
php artisan octane:start --server=roadrunner
php artisan octane:start --server=swoole
Worker
php artisan octane:start --workers=4
Con Swoole e task worker:
php artisan octane:start --workers=4 --task-workers=6
Watch file
php artisan octane:start --watch
Serve Node.js e Chokidar.npm install --save-dev chokidar
Comandi
php artisan octane:reload
php artisan octane:stop
php artisan octane:status
Attenzioni con la DI
Il codice resta in memoria: register/boot dei service provider vengono eseguiti una sola volta all’avvio.
Iniezione del container
// ❌ Il container "vecchio" viene riusato
$this->app->singleton(Service::class, function (Application $app) {
return new Service($app);
});
// ✅ Chiuso in closure per prendere sempre l'ultimo
$this->app->singleton(Service::class, function () {
return new Service(fn () => Container::getInstance());
});
L’helper globale app() e Container::getInstance() restituiscono sempre l’ultimo container.
Iniezione della request
// ❌
$this->app->singleton(Service::class, function (Application $app) {
return new Service($app['request']);
});
// ✅ Closure
$this->app->singleton(Service::class, function (Application $app) {
return new Service(fn () => $app['request']);
});
// ✅ Migliore: passa solo il valore necessario al metodo
$service->method($request->input('name'));
I type hint di Illuminate\Http\Request nei metodi controller/route sono sicuri. request() restituisce sempre la richiesta corrente.
Iniezione del config repository
// ❌
$this->app->singleton(Service::class, function (Application $app) {
return new Service($app->make('config'));
});
// ✅
$this->app->singleton(Service::class, function () {
return new Service(fn () => Container::getInstance()->make('config'));
});
L’helper config() restituisce sempre l’ultimo.
Memory leak
Attenzione a static che accumulano dati:
// ❌ Cresce a ogni richiesta
class Service
{
public static array $data = [];
}
public function index(Request $request): array
{
Service::$data[] = Str::random(10);
return [];
}
max-requests
Riavvia i worker dopo N richieste (default 500):
php artisan octane:start --max-requests=250
Tempo massimo di esecuzione
In config/octane.php (default 30s):
'max_execution_time' => 30,
Riavvia Octane dopo modifiche.
Task concorrenti (solo Swoole)
use App\Models\User;
use App\Models\Server;
use Laravel\Octane\Facades\Octane;
[$users, $servers] = Octane::concurrently([
fn () => User::all(),
fn () => Server::all(),
]);
Task worker con --task-workers.
php artisan octane:start --workers=4 --task-workers=6
Max 1024 task per chiamata (limite Swoole).
Tick e Interval (solo Swoole)
use Laravel\Octane\Facades\Octane;
Octane::tick('delayed-ticker', fn () => ray('Ticking...'))
->seconds(10);
Octane::tick('immediate-ticker', fn () => ray('Ticking...'))
->seconds(10)
->immediate();
Octane cache (solo Swoole)
Fino a 2 milioni di ops/s.
use Illuminate\Support\Facades\Cache;
Cache::store('octane')->put('framework', 'Laravel', 30);
Interval cache
use Illuminate\Support\Str;
Cache::store('octane')->interval('random', function () {
return Str::random(10);
}, seconds: 5);
I dati si perdono al riavvio.
Tabelle Swoole (solo Swoole)
In config/octane.php sezione tables:
'tables' => [
'example:1000' => [
'name' => 'string:1000',
'votes' => 'int',
],
],
use Laravel\Octane\Facades\Octane;
Octane::table('example')->set('uuid', [
'name' => 'Nuno Maduro',
'votes' => 1000,
]);
$row = Octane::table('example')->get('uuid');
Tipi supportati: string, int, float. I dati si perdono al riavvio.
Produzione
Nginx + Octane
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
server_name example.com;
root /home/forge/example.com/public;
location /index.php {
try_files /not_exists @octane;
}
location / {
try_files $uri $uri/ @octane;
}
location @octane {
set $suffix "";
if ($uri = /index.php) {
set $suffix ?$query_string;
}
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header SERVER_PORT $server_port;
proxy_set_header REMOTE_ADDR $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://127.0.0.1:8000$suffix;
}
}
Supervisor
[program:octane]
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/example.com/artisan octane:start --server=frankenphp --host=127.0.0.1 --port=8000
autostart=true
autorestart=true
user=forge
redirect_stderr=true
stdout_logfile=/home/forge/example.com/storage/logs/octane.log
stopwaitsecs=3600
HTTPS
Laravel Cloud
Installa il pacchetto
composer require laravel/octane
Attiva Octane in Laravel Cloud
Nel cluster compute App attiva “Use Octane as runtime”, salva e deploya.
Vedi la documentazione Laravel Cloud.
Reload dopo il deploy
php artisan octane:reload