Ga naar inhoud

Cache layer

Status: geïntegreerd en lokaal bewezen, 27 augustus 2026. Geen fase-taak in Taken (caching stond nergens gepland); vooruitgetrokken zodat /api/platform/revalidate uit taak 2.2 straks iets echts te doen heeft.

Eerste poging (26 augustus 2026): hand-rolled generation-counter cache. Een module-scoped Map in apps/site-template/src/lib/page-cache.ts, een middleware-hook in servePublicContent(), en invalidateAll()-aanroepen verspreid over de CMS-acties. Volledig gebouwd, gereviewd (twee bugs gevonden en gefixt: ongebonden cache-groei via query-strings, een race tussen een mutatie en een lopende render) en lokaal bewezen met astro dev.

Ontdekt vlak daarna: dit bestond al, beter. feature/route-cache (eigen branch, 19 augustus 2026, nooit als PR geopend) loste hetzelfde probleem op met Astro’s eigen route-cache (cache + memoryCache in astro.config.mjs, stabiel sinds Astro 7.0 — geverifieerd tegen de geïnstalleerde astro@7.2.0 in node_modules, niet aangenomen). Die aanpak wint op meerdere punten tegelijk:

  • Zit vóór de middleware. Geverifieerd in de Astro-broncode (astro/dist/core/routing/handler.js): de cache-handler krijgt de hele middleware-keten als zijn next, en memoryCache’s onRequest roept die next alleen aan bij een MISS. Een HIT raakt dus geen sessielookup, geen render, geen database — de eigen page-cache.ts-poging betaalde de sessielookup nog op élke request, ook bij een hit.
  • Tag-based, niet blanket. Eén CMS-mutatie purge’t precies wat hij raakt (rowTag(entity, id), SERVICES_TAG, SITEMAP_TAG, …) in plaats van een generatie-teller die bij élke mutatie de hele cache liet vervallen.
  • Los de exacte twee bugs op die in de eigen poging gevonden en gefixt waren — onafhankelijk, want dit is ouder werk: de provider sluit trackingparameters (utm_*, fbclid, …) standaard uit van de cache-key en houdt een LRU-cap van 500 entries aan, en de redirect-immutability-bug (zie hieronder) stond er al in gefixt.
  • Stale-while-revalidate. Na maxAge (300s) serveert Astro de oude HTML meteen en rendert op de achtergrond opnieuw; een bezoeker wacht nooit op een miss zodra de cache ooit warm is geweest.
  • Handelt een slugwijziging expliciet af (purge van het oude pad) — de eigen poging deed dit alleen impliciet, via de blanket-invalidatie.

Ontbrekend in de eerste poging, nu wel gedekt: query-string-groei (native cache: whitelist/LRU in plaats van pathname-only), Set-Cookie-uitsluiting (native cache doet dit ook, zelfstandig geverifieerd in memory-provider.js).

Nieuwe kosten van de omschakeling, niet aanwezig in de eerste poging: astro dev levert onvoorwaardelijk een no-op-cache — geen enkele HIT, ongeacht config (astro/dist/core/cache/handler.js: runtimeMode === "development"NoopAstroCache). Cache-gedrag bewijzen kan dus niet met de snelle dev-loop; dat vraagt pnpm run build + node dist/server/entry.mjs. Zie Architectuur § Renderstrategie voor het volledige mechanisme.

  1. page-cache.ts en de bijbehorende middleware-hook/invalidateAll()- aanroepen zijn verwijderd (git checkout -- op elk geraakt bestand, want alles stond nog uncommitted).
  2. feature/route-cache’s src/lib/cache.ts, de astro.config.mjs- cache-config, en de cachePublicRoute()/purgePublicCache()/ purgeWholeSite()-aanroepen in alle negen publieke pagina’s en acht CMS-actiebestanden zijn overgezet — via git apply op de zeven bestanden die sinds main ongewijzigd waren, handmatig op cms-media.ts (die had security/admin-cms-hardening al herschreven).
  3. De redirect-immutability-fix stond al onafhankelijk in beide takken (zelfde diagnose, zelfde oplossing) — geen samenvoeging nodig.
  4. AGENTS.md (harde regel 6) en Architectuur (§ Renderstrategie, § Beveiliging) bijgewerkt met het native-cache-mechanisme.

Bewijs (27 augustus 2026, gebouwde server, niet astro dev)

Section titled “Bewijs (27 augustus 2026, gebouwde server, niet astro dev)”
  • MISS → HIT op een verse pagina, identieke body.
  • ?utm_source=fb&fbclid=abc123 hit dezelfde entry als de kale URL.
  • admin.localhost:4321/* draagt nooit X-Astro-Cache.
  • Granulariteit bewezen: na updatePage op /over-ons werd alleen die pagina een MISS; / bleef een HIT. Na createNavItem (whole-site purge) werden beide een MISS. Dat is precies het gedrag dat de generation-counter niet kon leveren.
  • Content na mutatie klopt (nieuwe titel zichtbaar).
  • Eigen timing, lokaal, vijf publieke routes: MISS ≈ 7–18 ms, HIT ≈ 1–2,5 ms. Indicatief, geen productiebenchmark.
  • Testmutaties teruggedraaid; demo-seed staat weer zoals hij was.
  • pnpm --filter site-template run typecheck en run build groen.
  • /api/platform/revalidate (taak 2.2) kan nu purgeWholeSite(cache) aanroepen in plaats van de eerder geplande no-op-stub — Taakplan 2.2 is hierop bijgewerkt.
  • Multi-replica cache-consistentie. memoryCache leeft in het proces; bij meer dan één replica per tenant mist elke replica de invalidate van de andere. Niet relevant bij de huidige schaal (één container per tenant). Zie Architectuur.
  • Coolify-deploy en de bijbehorende omgeving — nog steeds een los punt, ongewijzigd door deze taak.