Qu’est-ce qu’Octane
Laravel Octane est un package qui accélère fortement Laravel en utilisant des serveurs d’applications à haute performance.
Avec PHP-FPM classique, l’application démarre et s’arrête pour chaque requête. Avec Octane, l’application démarre une seule fois, reste en mémoire, et sert les requêtes suivantes très rapidement.
La grande différence avec PHP-FPM : le bootstrap (enregistrement des service providers, etc.) n’est plus refait à chaque requête. Un seul démarrage, puis un traitement ultra-rapide.
Serveurs supportés
Trois options :
| Serveur | Langage | Installation | Tâches concurrentes | Remarques |
|---|
| FrankenPHP | Go | Auto (binaire) | — | Recommandé. HTTP/3, Brotli |
| RoadRunner | Go | Auto (binaire) | — | Simple à configurer |
| Swoole | Extension PHP | Manuel (PECL) | ✅ | Tâches concurrentes, cache Octane |
Laravel Cloud recommande Octane avec FrankenPHP et le prend en charge en managé.
Installation et configuration
Installation
composer require laravel/octane
Setup
php artisan octane:install
Un prompt propose de choisir le serveur, puis config/octane.php est généré.
FrankenPHP
Octane télécharge automatiquement le binaire.
RoadRunner
Octane télécharge automatiquement le binaire.
Swoole
Installez l’extension via PECL.
Pour Open Swoole :
Démarrage
Serveur
Par défaut sur le port 8000 : http://localhost:8000.
Serveur spécifique
php artisan octane:start --server=frankenphp
php artisan octane:start --server=roadrunner
php artisan octane:start --server=swoole
Nombre de workers
php artisan octane:start --workers=4
Avec Swoole, --task-workers pour les workers de tâches :
php artisan octane:start --workers=4 --task-workers=6
Watcher
Redémarre automatiquement quand un fichier change.
php artisan octane:start --watch
--watch nécessite Node.js et Chokidar.npm install --save-dev chokidar
Autres commandes
# Recharge les workers (après déploiement)
php artisan octane:reload
# Arrêt
php artisan octane:stop
# Statut
php artisan octane:status
Injection de dépendances
Avec Octane, l’application est conservée en mémoire : les méthodes register / boot des providers ne s’exécutent qu’une fois au démarrage. Attention à ne pas injecter des instances anciennes de container ou de request.
Injection du container
Injecter le container dans un singleton fige un ancien container.
// ❌ Problème : ancien container réutilisé
$this->app->singleton(Service::class, function (Application $app) {
return new Service($app);
});
// ✅ Solution : closure qui renvoie le container courant
$this->app->singleton(Service::class, function () {
return new Service(fn () => Container::getInstance());
});
app() et Container::getInstance() renvoient toujours le container courant.
Injection de la requête
// ❌ Problème : ancienne requête réutilisée
$this->app->singleton(Service::class, function (Application $app) {
return new Service($app['request']);
});
// ✅ Solution : closure vers la requête courante
$this->app->singleton(Service::class, function (Application $app) {
return new Service(fn () => $app['request']);
});
// ✅ Le mieux : passer les valeurs nécessaires en argument
$service->method($request->input('name'));
Type-hinter Illuminate\Http\Request dans une méthode de contrôleur reste sûr. request() retourne également la requête courante.
Injection du repository de configuration
// ❌ Problème : ancien repository réutilisé
$this->app->singleton(Service::class, function (Application $app) {
return new Service($app->make('config'));
});
// ✅ Solution
$this->app->singleton(Service::class, function () {
return new Service(fn () => Container::getInstance()->make('config'));
});
config() retourne toujours la configuration courante.
Fuites mémoire
Comme l’application vit en mémoire, cumuler des données dans des propriétés statiques crée des fuites.
// ❌ Fuite : $data grossit à chaque requête
class Service
{
public static array $data = [];
}
public function index(Request $request): array
{
Service::$data[] = Str::random(10);
return [];
}
max-requests pour recycler les workers
Redémarre le worker après N requêtes. Défaut : 500.
php artisan octane:start --max-requests=250
Durée d’exécution max
Dans config/octane.php, défaut 30 s.
'max_execution_time' => 30,
Redémarrez Octane après modification.
Tâches concurrentes (Swoole uniquement)
Octane::concurrently() exécute plusieurs closures en parallèle.
use App\Models\User;
use App\Models\Server;
use Laravel\Octane\Facades\Octane;
[$users, $servers] = Octane::concurrently([
fn () => User::all(),
fn () => Server::all(),
]);
Elles s’exécutent dans des « task workers » séparés. Ajustez leur nombre avec --task-workers.
php artisan octane:start --workers=4 --task-workers=6
Maximum 1 024 tâches par appel (limite Swoole).
Tick et interval (Swoole uniquement)
Exécutez périodiquement du code dans un boot de provider.
use Laravel\Octane\Facades\Octane;
// Toutes les 10 s
Octane::tick('delayed-ticker', fn () => ray('Ticking...'))
->seconds(10);
// Exécute aussi immédiatement au démarrage
Octane::tick('immediate-ticker', fn () => ray('Ticking...'))
->seconds(10)
->immediate();
Cache Octane (Swoole uniquement)
Cache en mémoire ultra rapide utilisant les Swoole Tables. Jusqu’à 2 millions d’opérations/s.
use Illuminate\Support\Facades\Cache;
Cache::store('octane')->put('framework', 'Laravel', 30);
Interval cache
Cache auto-actualisé.
use Illuminate\Support\Str;
Cache::store('octane')->interval('random', function () {
return Str::random(10);
}, seconds: 5);
Les données sont perdues au redémarrage.
Swoole Tables (Swoole uniquement)
Tables partagées entre workers, définies dans config/octane.php.
'tables' => [
'example:1000' => [
'name' => 'string:1000',
'votes' => 'int',
],
],
Accès :
use Laravel\Octane\Facades\Octane;
Octane::table('example')->set('uuid', [
'name' => 'Nuno Maduro',
'votes' => 1000,
]);
$row = Octane::table('example')->get('uuid');
Types autorisés : string, int, float. Données perdues au redémarrage.
Exploitation en production
Nginx + Octane
Typiquement, Nginx sert les fichiers statiques et termine le SSL, puis proxie vers 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
Gardez Octane démarré via 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
Activer HTTPS
Pour générer des URLs HTTPS via Octane :
Laravel Cloud
Laravel Cloud prend Octane + FrankenPHP en charge en managé. Pas de config Nginx / Supervisor : deux étapes.
Installer le package
composer require laravel/octane
Activer Octane sur Laravel Cloud
Ouvrez les paramètres de compute App, activez « Use Octane as runtime », enregistrez et déployez. Cloud construit et démarre l’app avec FrankenPHP + Octane.
Voir la documentation Laravel Cloud.
Rechargement après déploiement
Après un déploiement, rechargez les workers pour charger le nouveau code.
php artisan octane:reload