Almacenamiento en Caché GraphQL SWR (NestJS, code-first)
Resumen
Almacena en caché por intención, no por mecanismo. Una forma de política, un flujo de eventos observable, una traza por solicitud. Monta a nivel de servicio por defecto; escala a nivel de campo / operación / transporte solo cuando se mide.
Tres verdades difíciles que moldean cada decisión:
- Apollo Server no tiene stale-while-revalidate incorporado. Su
responseCachePlugines solo TTL y a nivel de operación. El SWR real proviene de tu propia capa (async-cache-dedupe, omercurius-cacheen el driver Mercurius) o de una CDN. - El alcance por defecto es
public. Una entrada pública es compartida textualmente por cada llamante, por lo que solo es correcta cuando el resultado es idéntico byte a byte para todos ellos. En cuanto un valor varía por llamante, debe marcarseperUser— o se produce una fuga. - Los interceptores de Nest no envuelven métodos de servicio, y
CacheInterceptorde@nestjs/cache-managerno funciona en GraphQL. Por lo tanto, el decorador a nivel de servicio que necesitas es un envoltorio de método sobre un motor de deduplicación — no un interceptor del framework.
Cuándo Usarlo
- NestJS GraphQL (code-first) donde los resolutores/servicios acceden repetidamente a una base de datos o API externa.
- Necesitas eliminar picos de latencia y estampidas al expirar el TTL (SWR real).
- Necesitas razonar sobre la seguridad/fugas de caché multiusuario.
- Necesitas visibilidad sobre las decisiones de acierto / obsoleto / fallo.
- Necesitas desactivar completamente el almacenamiento en caché — desarrollo, CI, o un incidente — con una sola bandera (ver Sección 1,
setup-disable-switch). - Estás cableando la capacidad de caché en una aplicación por primera vez (ver Sección 1).
Cuándo NO usarlo:
- Ya estás detrás de una CDN que hace almacenamiento en caché de respuestas para tráfico GET/APQ público — empieza ahí.
- Rutas de escritura/mutación, o datos por usuario sin reutilización y baja amplificación de lectura (el almacenamiento en caché añade riesgo para poca ganancia).
El Contrato de Callbacks
key, @CacheTag y @InvalidateTags aceptan funciones. Ajusta sus argumentos correctamente o la caché falla silenciosamente y las etiquetas fallan silenciosamente al purgar.
| Callback | Firma | Qué es args |
|---|---|---|
key | (args, ctx) => unknown[] | Promise<unknown[]> | la lista de argumentos del método, en orden de llamada — args[0], nunca args.id |
@CacheTag | (result, args) => string[] | null | la misma lista; result es el valor de retorno del método |
@InvalidateTags | (result, args) => string[] | la misma lista; result es el valor de retorno de la escritura |
- Posicional, no nombrado. Para
getTitle(id: string), el id esargs[0]. - Result viene primero en ambos callbacks de etiquetas. El
referencesdel motor base es(args, key, result)— orden diferente, primer argumento diferente (verdriver-async-cache-dedupe). ctx(userId,tenantId,locale, másgen) se deriva de la solicitud y es ensamblado porbuildCacheContext; está vacío fuera de una solicitud, por lo que un trabajo pasa lo que necesita como argumento.- Tipado: los valores por defecto son
unknown[]/unknown— anota la tupla (@Cacheable<[string]>,@CacheTag<[string]>) o los cuerpos de los callbacks no compilarán. - A nivel de campo es diferente: allí
argses el objeto de argumentos nombrados del resolutor yctxes el contexto GraphQL (driver-mercurius-cache).
Contrato completo, el paquete de clave { a, k, u }, y los casos extremos de serialización: policy-key-derivation. Implementación en tiempo de ejecución: setup-decorator-runtime.
Categorías de Reglas por Prioridad
| Prioridad | Categoría | Impacto | Prefijo |
|---|---|---|---|
| 1 | Configuración Única | CRÍTICO | setup- |
| 2 | Política de Caché | CRÍTICO | policy- |
| 3 | Seguridad contra Fugas | CRÍTICO | safety- |
| 4 | Invalidación | ALTO | invalidation- |
| 5 | Observabilidad | MEDIO | observability- |
| 6 | Drivers | MEDIO | driver- |
Referencia Rápida
1. Configuración Única (CRÍTICO)
setup-decorator-runtime- Implementa los Decoradores como Envoltorios de Método con Nombres Establessetup-disable-switch- Entrega un Interruptor de Configuración que Evita la Caché a Nivel de Serviciosetup-engine-choice- Usa un Motor de Deduplicación, y Cuenta el TTL en Segundossetup-fail-open- Fallo Abierto, y Nunca Cachees Erroressetup-file-placement- Coloca la Capacidad por Quién la Importasetup-identity-context- Lee el Llamante desde AsyncLocalStorage, No de Scope.REQUESTsetup-module-wiring- Cablea el Módulo de Caché una Vez con forRootAsyncsetup-storage-and-invalidation- Habilita la Invalidación y Establece referencesTTL y GC
2. Política de Caché (CRÍTICO)
policy-five-knobs- Conoce los Cinco Mandospolicy-key-derivation- Deriva la Clave Automáticamente, Nunca con JSON.stringifypolicy-mount-at-service- Monta a Nivel de Servicio por Defectopolicy-one-writing-pattern- Los Decoradores Son el Único Patrón de Escriturapolicy-service-escape-hatch- La API del Servicio es una Válvula de Escape, No un Segundo Patrón
3. Seguridad contra Fugas (CRÍTICO)
safety-default-public- El Alcance por Defecto es Público — Marca las Lecturas que Varían por Llamante como perUsersafety-key-dimensions- El Alcance Cubre Solo al Usuario — Cada Otra Dimensión Va en la Clavesafety-no-leak-checklist- Ejecuta la Lista de Verificación Sin Fugas en Cada Lectura Cacheada
4. Invalidación (ALTO)
invalidation-after-success- Invalida Solo Después de una Escritura Exitosainvalidation-atomic-purge- Purga Atómicamente y Limita la Cardinalidad de Etiquetasinvalidation-generation-prefix- Usa un Prefijo de Generación para Dominios Enormes o Gruesosinvalidation-tags-purge-only- Las Etiquetas Son Solo para Purgar, Nunca para Búsqueda
5. Observabilidad (MEDIO)
observability-limits-of-events- Conoce lo que el Motor No Puede Reportarobservability-metrics-and-tests- Rastrea las Métricas que Prueban la Solución, y Prueba sobre Resultadosobservability-per-request-trace- Expón una Traza por Solicitud, Solo en Desarrollo en GraphQLobservability-structured-events- Emite Eventos de Caché Estructurados, No Cadenas de Log
6. Drivers (MEDIO)
driver-apollo-response-cache- Opción C — Apollo responseCachePlugin (Nivel de Operación, Solo TTL)driver-apollo-vs-mercurius- Elige la Opción a Nivel de Campo Según tu Driverdriver-async-cache-dedupe- Opción A — async-cache-dedupe (Nivel de Servicio, Agnóstico de Transporte)driver-cdn-transport- Opción E — Transporte / CDN SWR (Solo Lecturas Públicas)driver-envelop-response-cache- Opción D — Envelop useResponseCache (No Nativo de NestJS)driver-federation-router- Solo Federación — Almacenamiento en Caché de Respuestas del Router Apollodriver-mercurius-cache- Opción B — mercurius-cache (Nivel de Campo, SWR Real)driver-version-pinning- Fija Versiones — Esta Área se Desvía
Cómo Usarlo
Comienza con la sección de Configuración Única, luego lee las reglas de política, seguridad e invalidación para la decisión que tienes delante. Los archivos de reglas viven bajo rules/:
rules/setup-module-wiring.md
rules/_sections.md
Cada archivo de regla contiene:
- Qué es la regla y el fallo que previene
- Un ejemplo incorrecto con una explicación
- Un ejemplo correcto con una explicación
- Referencias
Documento Compilado Completo
Para la guía completa con todas las reglas expandidas en un solo documento, consulta AGENTS.md.