Mise en cache adaptée aux variations
Certaines inclusions ont le même src mais un contenu différent selon la personne qui le demande. Le tableau des tarifs présente différents forfaits pour les administrateurs par rapport aux utilisateurs gratuits. Le système de navigation affiche « Tableau de bord » ou « Connexion » en fonction de l'authentification. Le héros est en français pour les utilisateurs français.
L'attribut vary déclare sur quelles dimensions de requête cette inclusion varie. bext calcule la clé de cache à partir du chemin source plus les valeurs de dimension déclarées, produisant un fragment mis en cache distinct par combinaison (dim × dim ×...).
<bext-include src="/partials/pricing-table"
vary="role,locale,geo"
ttl="10m"
></bext-include>
Même balise HTML. Entrées de cache séparées pour admin/en/US vs viewer/fr/FR vs admin/fr/DE.
Dimensions prises en charge#
Les valeurs proviennent du contexte de la requête, extraites par le middleware bext. Vous pouvez les référencer dans n'importe quelle inclusion vary :
| Dimension | Source | Exemples de valeurs |
|---|---|---|
role |
Session d'authentification | admin, editor, viewer, anonymous |
auth |
Session d'authentification (grossière) | authenticated, anonymous |
locale |
En-tête ou cookie Accept-Language |
en, fr, de, ja |
geo |
En-têtes GeoIP / CDN | US, FR, DE, JP |
device |
Classement User-Agent |
mobile, tablet, desktop |
theme |
Cookie ou en-tête | light, dark, auto |
currency |
Session ou géo-dérivé | USD, EUR, GBP |
Plus toutes les dimensions personnalisées définies dans bext.config.toml :
[include.vary.custom]
"preferred-unit" = { source = "cookie", name = "unit" }
"api-version" = { source = "header", name = "x-api-version" }
Dérivation de la clé de cache#
La clé est un hachage FNV-1a stable de 64 bits de :
hash(src || "\0" || sorted_vary_pairs)
Seules les dimensions déclarées dans la liste vary de l'inclusion contribuent à la clé. Une requête avec role=admin, locale=fr, geo=US frappant une inclusion avec vary="role,locale" produit la même clé de cache qu'une requête avec les mêmes role et locale mais un geo différent.
// Request A: role=admin, locale=fr, geo=US
// Request B: role=admin, locale=fr, geo=FR
// Include: vary="role,locale"
// → same cache key (geo ignored for this include)
// Request C: role=viewer, locale=fr, geo=US
// Include: vary="role,locale"
// → different cache key (role changed)
C'est ainsi qu'un élément peut produire N entrées de cache - une par combinaison unique de valeurs qui intéressent réellement l'inclusion.
Contrôle de cardinalité#
Une dimension variable avec trop de valeurs distinctes remplit le cache avec des entrées ponctuelles. Si vous variez sur locale avec 50 paramètres régionaux, vous disposez de 50 entrées de cache. Variez sur locale et role avec 4 rôles, vous disposez de 200 entrées. Ajoutez geo avec 100 pays et vous en avez 20 000.
bext suit la cardinalité et avertit lorsqu'une seule inclusion produit trop de variantes :
WARN include vary cardinality: src="/partials/pricing" dim="locale"
has 47 unique values — consider grouping (en, fr, de, zh, *)
Limitez les variantes par inclusion dans la configuration :
[include.cache]
max_variants_per_include = 100
En cas de dépassement, la variante la plus froide est expulsée du LRU. Cela limite l’utilisation de la mémoire quelle que soit la forme du trafic.
La cardinalité s'aggrave rapidement : vary="locale,role,geo" avec 50 paramètres régionaux × 4 rôles × 100 pays = 20 000 entrées de cache possibles. Définissez max_variants_per_include dans [include.cache] et préférez les regroupements plus grossiers (par exemple en/fr/de/zh/* ) pour les dimensions à cardinalité élevée.
Les inclusions authentifiées doivent varier#
Si une inclusion contient auth="required" ou role="...", elle doit inclure la dimension appropriée dans vary lorsqu'elle est mise en cache - sinon le cache servirait la barre d'outils d'administration aux utilisateurs anonymes (empoisonnement du cache).
<!-- WRONG: admin content will leak to non-admins -->
<bext-include src="/partials/admin"
auth="required" role="admin" ttl="30m"
></bext-include>
<!-- RIGHT: cached per role -->
<bext-include src="/partials/admin"
auth="required" role="admin"
ttl="30m" vary="role"
></bext-include>
bext enregistre un avertissement lorsque les inclusions authentifiées sont mises en cache sans variation de rôle. En mode strict (configurable), le cache est désactivé pour de telles inclusions plutôt que de diffuser un contenu potentiellement erroné.
Seules les dimensions répertoriées dans [include.vary.dimensions] (ou [include.vary.custom] ) sont reconnues. Le référencement à une dimension non déclarée dans vary="..." est ignoré en silence : cela ne contribuera pas à la clé de cache.
SSI et ESI#
SSI et ESI n'ont pas d'attribut vary sur la balise. Déclarez plutôt variant dans les règles de configuration :
[[include.rules]]
pattern = "/partials/pricing*"
vary = ["role", "locale"]
ttl = "10m"
Toute inclusion correspondante – bext -native, SSI ou ESI – obtient cette configuration variable.
<!-- all three get vary="role,locale" from the rule above -->
<bext-include src="/partials/pricing" ttl="10m"></bext-include>
<!--#include virtual="/partials/pricing" -->
<esi:include src="/partials/pricing" />
Utilisation de la variation dans les résolveurs#
Les résolveurs personnalisés reçoivent les valeurs variables dans le contexte de la demande :
impl IncludeResolver for MyResolver {
fn resolve(&self, d: &IncludeDirective, ctx: &IncludeContext) -> Option<String> {
let role = ctx.vary_value("role").unwrap_or("anonymous");
let locale = ctx.vary_value("locale").unwrap_or("en");
Some(render_pricing_for(role, locale))
}
}
Les clés de couche de cache sur ces valeurs sont automatiquement basées sur l'attribut vary de l'inclusion. Le résolveur lui-même les lit simplement.
Dimensions personnalisées#
Ajoutez des dimensions variables spécifiques à la demande dans la configuration :
# Example: vary on a feature-flag cookie
[include.vary.custom]
"beta-features" = { source = "cookie", name = "bext_beta" }
# Example: vary on an API version header
"api-version" = { source = "header", name = "x-api-version" }
Utilisez-les comme n'importe quelle dimension intégrée :
<bext-include src="/partials/api-docs"
vary="api-version"
ttl="1h"
></bext-include>
Désormais, chaque version de l'API dispose de sa propre copie en cache de la documentation.
Voir aussi#
- La mise en cache inclut — TTL, SWR, balises
- Les inclusions authentifiées — pourquoi varier sur les sujets
role - Configuration — dimensions et règles personnalisées
- Mise en cache avancée — Architecture de cache à plusieurs niveaux de bext