Mise en cache GraphQL SWR (NestJS, code-first)
Vue d'ensemble
Mettez en cache par intention, pas par mécanisme. Une seule forme de politique, un seul flux d'événements observable, une seule trace par requête. Montez au niveau service par défaut ; passez au champ / opération / transport uniquement lorsque mesuré.
Trois vérités fondamentales qui guident chaque décision :
- Apollo Server n'a pas de stale-while-revalidate intégré. Son
responseCachePluginest limité au TTL et au niveau opération. Le vrai SWR vient de votre propre couche (async-cache-dedupe, oumercurius-cachesur le pilote Mercurius) ou d'un CDN. - La portée par défaut est
public. Une entrée publique est partagée textuellement par tous les appelants, donc elle n'est correcte que lorsque le résultat est identique octet pour octet pour tous. Dès qu'une valeur varie selon l'appelant, elle doit être marquéeperUser— sinon elle fuit. - Les intercepteurs Nest ne encapsulent pas les méthodes de service, et le
CacheInterceptorde@nestjs/cache-managerne fonctionne pas avec GraphQL. Donc le décorateur au niveau service que vous voulez est un encapsuleur de méthode sur un moteur de déduplication — pas un interceptor framework.
Quand utiliser
- NestJS GraphQL (code-first) où les résolveurs/services accèdent à une base de données ou à une API externe de manière répétée.
- Vous devez éliminer les pics de latence et les ruées à l'expiration du TTL (vrai SWR).
- Vous devez raisonner sur la sécurité du cache multi-utilisateurs / les fuites.
- Vous avez besoin de visibilité sur les décisions hit / stale / miss.
- Vous devez désactiver entièrement la mise en cache — dev, CI, ou incident — avec un seul indicateur (voir Section 1,
setup-disable-switch). - Vous mettez en place la fonctionnalité de cache dans une application pour la première fois (voir Section 1).
Quand NE PAS utiliser :
- Vous êtes déjà derrière un CDN faisant de la mise en cache de réponses pour le trafic public GET/APQ — commencez par là.
- Chemins d'écriture/mutation, ou données par utilisateur sans réutilisation et avec une faible amplification de lecture (la mise en cache ajoute du risque pour peu de gain).
Le contrat des callbacks
key, @CacheTag et @InvalidateTags prennent des fonctions. Maîtrisez leurs arguments ou le cache
échoue silencieusement et les tags ne se purgent pas silencieusement.
| Callback | Signature | Ce qu'est args |
|---|---|---|
key | (args, ctx) => unknown[] | Promise<unknown[]> | la liste d'arguments de la méthode, dans l'ordre d'appel — args[0], jamais args.id |
@CacheTag | (result, args) => string[] | null | la même liste ; result est la valeur de retour de la méthode |
@InvalidateTags | (result, args) => string[] | la même liste ; result est la valeur de retour de l'écriture |
- Positionnel, pas nommé. Pour
getTitle(id: string), l'id estargs[0]. - Le résultat vient en premier pour les deux callbacks de tag. Les
referencesdu moteur brut sont(args, key, result)— ordre différent, premier argument différent (voirdriver-async-cache-dedupe). ctx(userId,tenantId,locale, plusgen) est dérivé de la requête et assemblé parbuildCacheContext; il est vide en dehors d'une requête, donc un job passe ce dont il a besoin comme argument.- Typage : les valeurs par défaut sont
unknown[]/unknown— annotez le tuple (@Cacheable<[string]>,@CacheTag<[string]>) ou les corps des callbacks ne compileront pas. - Le niveau champ est différent : ici
argsest l'objet d'arguments nommés du résolveur etctxest le contexte GraphQL (driver-mercurius-cache).
Contrat complet, le bundle de clé { a, k, u }, et les cas limites de sérialisation :
policy-key-derivation. Implémentation d'exécution : setup-decorator-runtime.
Catégories de règles par priorité
| Priorité | Catégorie | Impact | Préfixe |
|---|---|---|---|
| 1 | Configuration Unique | CRITIQUE | setup- |
| 2 | Politique de Cache | CRITIQUE | policy- |
| 3 | Sécurité contre les Fuites | CRITIQUE | safety- |
| 4 | Invalidation | HAUTE | invalidation- |
| 5 | Observabilité | MOYENNE | observability- |
| 6 | Pilotes | MOYENNE | driver- |
Référence rapide
1. Configuration Unique (CRITIQUE)
setup-decorator-runtime- Implémentez les Décorateurs comme Encapsuleurs de Méthode avec des Noms Stablessetup-disable-switch- Livrez un Commutateur de Configuration Qui Contourne le Cache au Niveau Servicesetup-engine-choice- Utilisez un Moteur de Déduplication et Comptez le TTL en Secondessetup-fail-open- Échouez Ouvertement et Ne Mettez Jamais les Erreurs en Cachesetup-file-placement- Placez la Fonctionnalité en Fonction de Qui l'Importesetup-identity-context- Lisez l'Appelant depuis AsyncLocalStorage, Pas depuis Scope.REQUESTsetup-module-wiring- Câblez le Module de Cache une Fois avec forRootAsyncsetup-storage-and-invalidation- Activez l'Invalidation et Définissez referencesTTL et GC
2. Politique de Cache (CRITIQUE)
policy-five-knobs- Connaissez les Cinq Boutonspolicy-key-derivation- Dérivez la Clé Automatiquement, Jamais avec JSON.stringifypolicy-mount-at-service- Montez au Niveau Service par Défautpolicy-one-writing-pattern- Les Décorateurs Sont le Seul Modèle d'Écriturepolicy-service-escape-hatch- L'API de Service Est une Porte de Sortie, Pas un Deuxième Modèle
3. Sécurité contre les Fuites (CRITIQUE)
safety-default-public- La Portée par Défaut est Publique — Marquez les Lectures Qui Varient par Appelant comme perUsersafety-key-dimensions- La Portée Couvre Uniquement l'Utilisateur — Toute Autre Dimension Va dans la Clésafety-no-leak-checklist- Exécutez la Checklist Sans Fuite sur Chaque Lecture en Cache
4. Invalidation (HAUTE)
invalidation-after-success- Invalidez Uniquement Après une Écriture Réussieinvalidation-atomic-purge- Purgez Atomiquement et Limitez la Cardinalité des Tagsinvalidation-generation-prefix- Utilisez un Préfixe de Génération pour les Domaines Très Larges ou Grossiersinvalidation-tags-purge-only- Les Tags Sont Uniquement pour la Purge, Jamais pour la Recherche
5. Observabilité (MOYENNE)
observability-limits-of-events- Sachez Ce Que le Moteur Ne Peut Pas Reporterobservability-metrics-and-tests- Suivez les Métriques Qui Prouvent la Correction et Testez sur les Résultatsobservability-per-request-trace- Affichez une Trace par Requête, Réservée au Développement sur GraphQLobservability-structured-events- Émettez des Événements de Cache Structurés, Pas des Chaînes de Log
6. Pilotes (MOYENNE)
driver-apollo-response-cache- Option C — Apollo responseCachePlugin (Niveau Opération, TTL Uniquement)driver-apollo-vs-mercurius- Choisissez l'Option au Niveau Champ de Votre Pilotedriver-async-cache-dedupe- Option A — async-cache-dedupe (Niveau Service, Agnostique au Transport)driver-cdn-transport- Option E — Transport / CDN SWR (Lectures Publiques Uniquement)driver-envelop-response-cache- Option D — Envelop useResponseCache (Pas Natif à NestJS)driver-federation-router- Fédération Uniquement — Mise en Cache des Réponses du Routeur Apollodriver-mercurius-cache- Option B — mercurius-cache (Niveau Champ, Vrai SWR)driver-version-pinning- Épinglez les Versions — Ce Domaine Évolue Rapidement
Comment utiliser
Commencez par la section Configuration Unique, puis lisez les règles de politique, sécurité et invalidation
pour la décision à prendre. Les fichiers de règles se trouvent sous rules/ :
rules/setup-module-wiring.md
rules/_sections.md
Chaque fichier de règle contient :
- Ce qu'est la règle et l'échec qu'elle prévient
- Un exemple incorrect avec une explication
- Un exemple correct avec une explication
- Références
Document complet compilé
Pour le guide complet avec toutes les règles développées dans un seul document, voir AGENTS.md.