Intégration Laravel
bext exécute Laravel à l'intérieur du processus Edge. Contrairement à l'intégration Rails - qui inverse le proxy vers un Puma externe - bext intègre libphp via un SAPI personnalisé ( crates/bext-php ) et envoie chaque requête à un noyau Laravel conservé dans la mémoire du thread de travail. Il n'y a pas de php-fpm, pas de socket FastCGI, pas de sous-processus. Un binaire sert TLS, HTTP/2/3, WAF, cache et PHP.
Le mode Worker va plus loin : le noyau Laravel démarre une fois par thread de travail au démarrage, et chaque requête ultérieure réutilise ce noyau via une boucle bext_handle_request(...). La surcharge par requête passe du classique 1 à 5 ms (chargement automatique du Composer + reconstruction de la configuration + câblage du conteneur) à environ 34 us (réutilisation du noyau + cycle GC).
Quand l’utiliser. Si vous avez déjà un projet Laravel et vous voulez un serveur Edge + application mono-binaire sans opérations empreinte, cette intégration est faite pour vous. Si tu veux du classique FastCGI avec php-fpm, le proxy inverse de bext peut lui transmettre les requêtes, mais le mode intégré est strictement plus rapide et plus simple.
Architecture#
┌─────────┐ ┌───────────────────────────────────────┐
│ │ HTTPS │ bext │
│ client │ ───────► │ TLS • WAF • cache • obs • PHP kernel │
│ │ :443 │ :8080 │
└─────────┘ └───────────────────────────────────────┘
│
▼ (in-process, 34 us)
┌──────────────────┐
│ Laravel kernel │
│ (per worker) │
└──────────────────┘
Parcours d’une requête :
- Le client ouvre une connexion TLS vers bext sur
:443, ou:8080en développement. - bext termine TLS, exécute le WAF, vérifie le cache ISR et
achemine la requête. Les ressources statiques sous
/build/*,/storage/*,/favicon.icoet/robots.txtsont servies directement depuis le disque, sans faire appel à PHP. - Les requêtes dynamiques sont réparties entre les threads de travail PHP, au nombre de
workers. Le rappelbext_handle_request(...)du thread de travail s’active, le noyau de Laravel traite la requête, la réponse revient en streaming vers bext, puis bext l’envoie au client en HTTP/2 ou HTTP/3.
bext.config.toml#
La configuration du projet de démarrage, réduite à l’essentiel :
[server]
port = 8080
[php]
enabled = true
document_root = "./public"
worker_script = "./bootstrap/worker.php"
workers = 4
max_requests = 10000
max_execution_time = 30
[php.ini]
memory_limit = "256M"
post_max_size = "16M"
upload_max_filesize = "16M"
[waf]
enabled = true
[[route_rules]]
pattern = "/build/*"
render = "static"
[[route_rules]]
pattern = "/storage/*"
render = "static"
Champs principaux :
worker_script— chemin du fichier PHP qui initialise le noyau une fois par travailleur. Lorsqu'il n'est pas défini, bext revient en mode classique (démarrepublic/index.phppar requête).workers— nombre de noyaux parallèles contenus dans la RAM. Chaque travailleur est un contexte TSRM distinct ; sur NTS PHP, cela est limité à 1.max_requests— le travailleur est recyclé après autant de demandes de contenir des fuites de mémoire dans des packages tiers. bext le redémarre automatiquement sans aucune demande abandonnée.[php.ini]— n'importe quelle clé PHP INI ; bext définit une production raisonnable valeurs par défaut (OPcache activé, opcache.validate_timestamps=0, durcissement des fonctions désactivées, sandboxingopen_basedir, JIT désactivé par défaut).
Voir référence [php] pour la liste complète des champs.
bootstrap/worker.php#
Le cœur du mode travailleur. S'exécute une fois par thread au démarrage, puis boucle :
<?php
require __DIR__ . '/../vendor/autoload.php';
$app = require __DIR__ . '/app.php';
$kernel = $app->make(\Illuminate\Contracts\Http\Kernel::class);
while (bext_handle_request(function () use ($kernel) {
$response = $kernel->handle(
$request = \Illuminate\Http\Request::capture()
);
$response->send();
$kernel->terminate($request, $response);
})) {
gc_collect_cycles();
}
bext_handle_request est une fonction hôte exposée par bext -php. Il bloque jusqu'à ce qu'une requête arrive, appelle le rappel et renvoie
true — à moins que le travailleur ait atteint max_requests, auquel cas il renvoie false et la boucle while se termine proprement afin que bext puisse générer un travailleur de remplacement.
Ce que bext ajoute#
| Préoccupation | Qui s'en occupe |
|---|---|
| TLS / ACME | bext |
| HTTP/2, HTTP/3 (QUIC) | bext |
| WAF (bots, limite de débit) | bext |
| Cache périphérique (ISR/SWR) | bext |
| Compression (brotli) | bext |
| Métriques Prometheus | bext |
| Traces OpenTelemetry | bext |
| Service d'actifs statiques | bext (voir les règles d'itinéraire ci-dessus) |
| Exécution PHP | bext (libphp SAPI intégré) |
| Logique métier | Laravel |
| Éloquent / DB | Laravel |
| Files d'attente / tâches | Laravel (Horizon, synchronisation, base de données) |
| Artisan / migrations | Laravel |
Invalidation du cache à partir de Laravel#
Le package compagnon bext/laravel Composer enregistre les aides pour invalider le cache ISR de bext depuis l'intérieur d'un contrôleur :
class ProductController extends Controller
{
public function update(Request $request, string $id)
{
$product = Product::findOrFail($id)->update($request->all());
// Invalidate ISR cache entries tagged "products"
bext_invalidate("products");
return response()->json($product);
}
}
Voir la référence complète de l'assistant bext/laravel ci-dessous.
Aides et services#
Installez le package Composer compagnon pour déverrouiller les assistants de cache, en temps réel et de tâches :
composer require bext/laravel
Trois globaux sont alors disponibles partout :
bext_invalidate("products");
bext_publish("orders", ["id" => 123, "status" => "shipped"]);
bext_task("cleanup", "0 2 * * *", "cache::gc");
Ou injecter à partir du récipient :
app('bext.cache')->invalidate("products");
app('bext.realtime')->publish("orders", [...]);
app('bext.tasks')->register("daily-report", "0 9 * * 1-5", $url);
Détection#
Le scanner importation infrarouge de bext reconnaît un projet Laravel à partir de :
- un
composer.jsonqui déclarelaravel/framework, et - un fichier CLI
artisan
Lorsque les deux sont présents, bext infra import suggère le modèle d'intégration Laravel et propose un échafaudage à partir de @bext/starter-laravel.
L'entrée de catalogue réside dans crates/bext-import/catalog/frameworks.yaml :
- match:
any_of_files:
- "composer.json"
- "artisan"
composer:
any_of_packages:
- "laravel/framework"
extract:
framework: laravel
starter: "@bext/starter-laravel"
confidence: high
Le démarreur#
bext new my-laravel-app --template @bext/starter-laravel
cd my-laravel-app
composer install
bext serve
Visitez http://localhost:8080.
Le démarreur est un échafaudage , et non une application Laravel fonctionnelle. Il est livré avec la forme minimale dont bext a besoin : un composer.json, un contrôleur frontal, un bootstrap/worker.php, un minuscule HomeController et
Itinéraire web.php et un bext.config.toml avec le bloc [php] câblé. Utilisez composer create-project laravel/laravel pour générer un véritable projet Laravel et supprimez le démarreur
bext.config.toml + bootstrap/worker.php – c'est le flux de travail canonique.
Comment cela se compare à Rails#
| Dimension | bext + Rails | bext + Laravel |
|---|---|---|
| Modèle de processus | bext + Puma séparé | bext uniquement (PHP intégré) |
| Inter -saut de processus | Bouclage HTTP/1.1 | aucun — appel en cours |
| Frais généraux par requête | ~100 à 300 us (proxy) | ~34 nous (mode travailleur) |
| Langue d'exécution | Ruby (interprète externe) | PHP (libphp intégré) |
| Section de configuration | [upstreams.*] + proxy = |
[php] |
| unités système | 2 ( bext + rails-app.service) | 1 (bext) |
| Déployer l'artefact | Gemfile + arborescence d'applications + bext | compositeur + arborescence d'applications + bext |
L'asymétrie existe parce que les écosystèmes PHP et Ruby proposent des histoires d'intégration très différentes. libphp expose un SAPI stable intégré à des dizaines de serveurs Web ; Ruby ne le fait pas. Rails sous Puma est rapide et ergonomique, le chemin du proxy inverse HTTP est donc le bon compromis pour Rails. PHP intégré dans le processus est strictement plus rapide et plus simple pour Laravel.
Le mode Worker nécessite une version PHP ZTS (thread-safe). PHP non thread-safe (NTS) revient au démarrage classique par requête : pas de noyau persistant, pas de surcharge d'environ 34 µs. Utilisez la distribution PHP prédéfinie de bext (livrée ZTS par défaut) pour éviter une compilation PHP personnalisée.
Limites#
- Le mode Worker nécessite ZTS PHP. Constructions non thread-safe (NTS)
de PHP revient en mode classique (pas de noyau persistant). Créez PHP avec
--enable-ztspour débloquer le mode travailleur – ou utilisez la distribution PHP prédéfinie de bext qui fournit ZTS par défaut. - Aucune isolation de processus entre les demandes. Parce que les demandes
partagez le noyau du travailleur, un crash dans une requête fait planter l'ensemble du travailleur. bext redémarre automatiquement le travailleur et relit les requêtes en cours, mais ce n'est pas aussi infaillible que le modèle de processus par requête de php-fpm.
max_requestsaide à contenir les fuites lentes. - Le premier démarrage est lent. Le démarrage du noyau Laravel prend 100 à 300 ms.
opération. bext démarre tous les travailleurs simultanément au démarrage, de sorte que la première requête après
bext servepeut toucher les travailleurs froids jusqu'à ce qu'ils apparaissent tous. - Les extensions doivent être regroupées au moment de la génération. bext -liens php par rapport à un ensemble d'extensions organisé (pdo_mysql, pdo_pgsql, redis, gd, mbstring, intl, opcache). Les extensions personnalisées nécessitent une reconstruction de bext : elles ne peuvent pas être chargées au moment de l'exécution.
En rapport#
@bext/starter-laravel— l'échafaudage- Runtime PHP intégré — Référence de la section
[php] - TLS automatique — Certificats basés sur ACME
- WAF et sécurité — protections de bord
- Intégration des rails — contrepartie du proxy inverse
Links#
- Laravel — documentation officielle Laravel