ENbext.dev
DocumentationExtensions

Traduction automatique depuis l’anglais. Consulter l’original.

Sur cette page

Plugins Lua

Le niveau Lua exécute le code du plugin dans les états Lua 5.4 intégrés via mlua. Il s'agit du runtime de plug-in bext le plus petit et le plus rapide à démarrer : un état simple coûte environ 150 Ko de mémoire et évalue un petit script en moins d'une milliseconde. Alors que le niveau V8 est optimisé pour le débit JS brut sur un middleware qui gère chaque requête, le niveau Lua est optimisé pour les scripts rechargeables à chaud : politiques, transformations, limites de débit et étapes de transfert de données que les locataires peuvent souhaiter modifier sans passer par un déploiement.

Quand choisir Lua#

Choisissez Lua quand :

  • Vous souhaitez des scripts par locataire rechargeables à chaud. Le démarrage à froid de Lua est suffisamment faible pour que vous puissiez reconstruire l'état lors d'un changement de configuration sans impact mesurable sur le chemin de requête.
  • Votre plugin est petit et autonome. Un limiteur de débit, une décision politique, un réécrivain de requêtes sortantes — tout ce qui tient dans une page de script.
  • Vous avez besoin de la plus petite surcharge de mémoire possible. 150 Ko par état signifie que vous pouvez en conserver un par locataire en mémoire pour des milliers de locataires.
  • Vous préférez une surface linguistique minuscule et stable. Lua 5.4 n'a pas de gestionnaire de paquets, pas de macros et pas de terrier de lapin npm install - ce que vous voyez dans le script est ce qui s'exécute.

Choisissez autre chose lorsque :

  • Vous avez besoin de fonctionnalités JavaScript modernes, d'async/wait ou de l'écosystème NPM plus large : utilisez Plugins V8.
  • Vous avez besoin d’une vitesse de compilation quasi native pour le code gourmand en CPU – utilisez Plugins WASM.
  • Vous avez besoin d'un espace utilisateur Linux complet (déploiement, liaison de bibliothèques) - utilisez Plugins nsjail.

Caractéristiques d'exécution#

Propriété Défaut Configurable
Tas maximum 64 Mo LuaSandboxLimits::max_heap_bytes
Carburant par appel 200 ticks LuaSandboxLimits::fuel_per_call
Nombre de hooks (instructions VM par tick) 1,000 LuaSandboxLimits::hook_count
Démarrage à froid (par état) ~1 ms N/A
Frais généraux par état ~150 Ko résident N/A
Échauffement en piscine Désireux pool.size

Au démarrage, LuaPluginPool crée avec impatience les états size afin que le chemin de requête acquire() ne paie jamais de frais de démarrage à froid. Contrairement au niveau V8, les états Lua ne sont pas épinglés sur des threads de travail dédiés : mlua n'a aucune contrainte d'ordre d'abandon et l'adaptateur protège simplement l'état avec un mutex.

Le tableau des fonctions de l'hôte#

Les scripts invités appellent les fonctions hôte via une seule table globale bext installée au moment de la construction de l'adaptateur. Cela reflète exactement l'espace de noms bext.* du niveau V8 afin que les auteurs puissent translittérer entre les environnements d'exécution.

Les charges utiles qui traversent l'ABI sont des chaînes JSON. Un gestionnaire de middleware qui souhaite court-circuiter une réponse crée une chaîne JSON et la transmet à bext.middleware_respond(...) ; l'adaptateur Rust analyse l'enveloppe et la transforme en RequestAction::Respond(PluginResponse) natif.

Liaisons disponibles#

lua
-- Structured logging — routed to the host tracing pipeline.
bext.log("info", "request seen")
bext.log("warn", "slow DB query")
bext.log("error", "upstream 502")

-- Emit a metric — name, numeric value, optional JSON-stringified tags.
bext.emit_metric("requests_total", 1, '{"route":"/api/health"}')

-- Read the plugin's config section from bext.config.toml (returns a JSON string).
local cfg = bext.get_config()

-- Short-circuit a middleware request with a response envelope.
return bext.middleware_respond(
  '{"status":429,"headers":[["retry-after","60"]],"body":"slow down"}'
)

-- Continue down the middleware stack.
return bext.middleware_continue()

-- Cache observability — emits a structured event on the host tracing bus.
bext.cache_event("hit", "k1")

-- Lifecycle event — used by guest LifecyclePlugin scripts to log hook firings.
bext.lifecycle_event("request_complete", event_json)

-- Transform unchanged marker — guest TransformPlugin scripts use this to say
-- "this file wasn't rewritten".
return bext.transform_unchanged()

Les caractéristiques de fonctionnalités suivantes sont câblées aujourd'hui : Middleware, Cache, Lifecycle, Transform. Les fonctionnalités de base E1 (Auth, Session, Mailer, Tracer, Scheduled) et les fonctionnalités de niveau intermédiaire E2 (Webhook, FeatureFlag, I18n, StorageClient, SearchClient, AuthzPolicy, Locking) sont reportées à une session de suivi — voir crates/bext-plugin-lua/KNOWN_DIFFERENCES.md et les marqueurs TODO(E4 wave 2) dans host_functions.rs.

Hello World – un plugin Middleware#

Un plugin Lua est un script qui évalue une table dont les entrées sont les méthodes de traits de capacité. L'adaptateur charge le script une fois, met en cache la table renvoyée dans le registre Lua et appelle ses méthodes à chaque requête.

lua
-- my-middleware.lua
return {
  on_request = function(self, ctx_json)
    -- ctx_json is a serialised RequestContext. Decode what you need
    -- with a Lua-side JSON library or a cheap substring match.
    bext.log("info", "plugin saw: " .. ctx_json:sub(1, 80))
    return bext.middleware_continue()
  end,

  on_response = function(self, arg)
    -- arg is {"status":N,"headers":[[k,v]...]}
    -- Return nil to leave the response unchanged.
    return nil
  end,
}

Chargez-le depuis un hôte Rust :

rust
use bext_plugin_lua::{LuaPluginConfig, LuaPluginRuntime};
use bext_plugin_api::types::PluginManifest;

let rt = LuaPluginRuntime::new();
let source = std::fs::read_to_string("my-middleware.lua")?;
let manifest = PluginManifest {
    name: "my-middleware".into(),
    version: "0.1.0".into(),
    description: "".into(),
    capabilities: vec![],
    requires_capabilities: vec![],
    provides_capabilities: vec![],
    pure: false,
    state: None,
    lazy: false,
};
rt.load_plugin(LuaPluginConfig::new("my-middleware", manifest, source))?;

Plugin de référence : bext-ratelimit-lua#

crates/bext-impls/bext-ratelimit-lua est livré avec un petit limiteur de débit à fenêtre coulissante basé sur IP entièrement écrit en Lua. Le wrapper Rust comprend environ 50 lignes qui intègrent le fichier script.lua via include_str! et exposent un assistant new(). C'est la forme recommandée pour les plugins Lua de référence.

text
crates/bext-impls/bext-ratelimit-lua/
├── Cargo.toml       -- bext-plugin-api + bext-plugin-lua path deps
├── script.lua       -- the actual plugin logic (~50 lines of Lua)
└── src/lib.rs       -- thin Rust loader: pub const SCRIPT + pub fn new()

Exécutez ses tests :

bash
cargo test -p bext-ratelimit-lua

Comparaison avec V8 et WASM#

Dimension Lua V8 était
Langue Lua 5.4 Moderne JavaScript Rust / Go / C (compilé)
Démarrage à froid (par état) ~1 ms ~15 ms ~1 ms
Mémoire par instance ~150 Ko ~2 Mo ~500 Ko
Prise en charge asynchrone Non Différé Non (wasi-preview1)
Rechargement à chaud Oui (nouvel état par rechargement) Non (abandonner le bug) Oui
JIT Non (interprète uniquement) Oui Oui (Cranelift)
Taille de la bibliothèque standard Très petit Très grand Moyen (wasi)
Meilleur ajustement Scripts par locataire, vérifications de stratégie Middleware hot-path, transfert de données complexes Code compilé et gourmand en CPU

Différences connues#

Voir crates/bext-plugin-lua/KNOWN_DIFFERENCES.md pour la liste complète des écarts actuels par rapport aux niveaux wasmtime et V8, y compris les 12 emplacements de capacités E1/E2 non liés, les mises en garde concernant l'approximation du carburant et le suivi du renforcement de stdlib.

Conseil

Les états Lua sont gardés par un mutex, non épinglés à un thread de travail dédié. Cela signifie que vous pouvez regrouper en toute sécurité de nombreux états Lua sans la surcharge par thread du niveau V8 – idéal pour les scripts par locataire où vous pourriez avoir besoin de milliers d'états simultanés.

Remarque

Lua n'a pas de support asynchrone. Tout appel hôte bext.* bloque l’exécution de Lua pendant sa durée. Gardez les appels d'hôte individuels à gros grain et évitez les boucles bavardes par élément sur les fonctions de l'hôte.

En rapport#

  • Présentation du système de plugins — niveaux sandbox, types de fonctionnalités et priorité du middleware
  • Plugins QuickJS — Alternative à JavaScript avec une empreinte et un coût de démarrage similaires
  • Plugins V8 — JavaScript moderne avec JIT, async et un écosystème plus vaste
  • Plugins WASM — code compilé pour les plugins gourmands en CPU
  • Plugins nsjail — isolation complète des processus pour les plugins nécessitant des bibliothèques système
  • Édition — partagez votre plugin Lua sur le registre
Modifier cette page ↗Besoin d’aide ? ↗
Rechercher dans la documentation

Saisissez un sujet, une commande ou une question.