Terug naar blog
pimcachingapiperformancearchitectuur

Productdata uit een PIM cachen zonder verouderde data te tonen

8 mei 20269 min leestijd

Wie productdata uit een PIM zoals Akeneo of Pimcore toont op een website, loopt vroeg of laat tegen hetzelfde dilemma aan. Bevraag je het PIM live, dan is je site zo traag als de API van je PIM op het drukste moment van de dag. Cache je de data, dan loop je het risico dat een bezoeker een product ziet dat gisteren is uitgefaseerd. In dit artikel behandelen we de patronen die wij in de praktijk gebruiken om beide problemen tegelijk op te lossen.

Niet alle data is gelijk

De eerste stap is erkennen dat "productdata" geen homogene categorie is. Een typische productpagina combineert data met heel verschillende houdbaarheid:

  • Naam, omschrijving en specificaties veranderen zelden: lang cachen en invalideren op event.
  • Afbeeldingen en assets veranderen zelden: CDN met lange TTL en versioned URLs.
  • Categorisering en relaties veranderen soms: lang cachen en invalideren op event.
  • Lijstprijzen veranderen periodiek: kort cachen of invalideren op event.
  • Voorraad verandert continu: niet of hooguit seconden cachen, via een apart endpoint.
  • Klantspecifieke prijzen verschillen per request: nooit gedeeld cachen.

De grootste fout die we tegenkomen is een uniforme TTL over dit hele spectrum. Dan is je cache óf te kort voor de statische data (en bevraag je het PIM onnodig vaak), óf te lang voor voorraad (en verkoop je producten die er niet zijn).

TTL versus event-gebaseerde invalidatie

Een TTL is een gok: je raadt hoe lang data geldig blijft. Event-gebaseerde invalidatie verwijdert het gokken. Vrijwel elk modern PIM kan wijzigingen pushen, via webhooks of een message queue. Zodra een product wijzigt, invalideer je alleen de cache-entries die dat product raken:

final class ProductUpdatedHandler
{
    public function __construct(
        private TagAwareCacheInterface $cache,
    ) {}
 
    public function __invoke(ProductUpdated $event): void
    {
        $this->cache->invalidateTags([
            'product-' . $event->sku,
            'category-' . $event->categoryId,
        ]);
    }
}

Cache tags zijn hier essentieel. Een product leeft niet alleen op zijn eigen detailpagina, maar ook in categorieoverzichten, zoekresultaten en "gerelateerde producten"-blokken. Door elke cache-entry te taggen met de SKU's die erin voorkomen, kun je gericht invalideren in plaats van de hele cache te legen.

Het resultaat: statische productdata mag dagenlang in de cache leven, want zodra er iets wijzigt in het PIM, is de cache binnen enkele seconden bijgewerkt. Je hebt de snelheid van agressief cachen en de actualiteit van live bevragen.

Stale-while-revalidate: nooit wachten op de bron

Wat gebeurt er als een cache-entry verlopen of geïnvalideerd is en een bezoeker de pagina opvraagt? In een naïeve opzet wacht die bezoeker tot het PIM geantwoord heeft. Bij een trage of onbereikbare bron wordt jouw website daarmee zo onbetrouwbaar als de zwakste schakel.

Het stale-while-revalidate patroon lost dit op: serveer de verlopen versie direct en ververs op de achtergrond.

async function getProduct(sku: string): Promise<Product> {
  const cached = await cache.get(`product-${sku}`);
 
  if (cached && !cached.isStale) {
    return cached.value;
  }
 
  if (cached?.isStale) {
    void refreshInBackground(sku);
    return cached.value;
  }
 
  return await fetchAndCache(sku);
}

Een bijkomend voordeel: als het PIM een storing heeft, blijft je website gewoon draaien op de laatst bekende data. De bron mag plat, de etalage blijft open.

Cache stampedes voorkomen

Een klassieke valkuil bij druk bezochte pagina's: een populaire cache-entry verloopt en honderd gelijktijdige requests besluiten allemaal zelf de bron te bevragen. Het PIM krijgt in één seconde honderd identieke verzoeken en bezwijkt alsnog, precies op het moment dat het druk is.

De oplossing is een lock of "single flight": de eerste request ververst, de rest wacht op dat resultaat of krijgt de stale versie.

$product = $this->cache->get('product-' . $sku, function (ItemInterface $item) use ($sku) {
    $item->tag(['product-' . $sku]);
    return $this->pimClient->fetchProduct($sku);
}, beta: 1.0);

Symfony's cache-component heeft dit ingebouwd via probabilistic early expiration (de beta-parameter): entries worden vlak vóór hun werkelijke vervaltijd door één enkele request vernieuwd, zodat de massa de verse versie al aantreft.

Voorraad en prijs: cachen op de juiste laag

Voorraad en klantspecifieke prijzen horen niet thuis in dezelfde cache als productcontent. Onze aanpak: render de pagina volledig uit de productcache en haal volatiele data apart op via een licht endpoint, dat zelf hooguit enkele seconden microcachet. De pagina is dan instant uit de cache te serveren, terwijl voorraadindicatie en prijs asynchroon binnenkomen van een endpoint dat daarvoor gebouwd is.

Dit voorkomt ook de meest hardnekkige bug in dit soort architecturen: een "gecachte" klantspecifieke prijs die aan de verkeerde klant wordt getoond. Wat per klant verschilt, mag simpelweg nooit in een gedeelde cache belanden.

Maak het meetbaar

Een cachingstrategie zonder metingen is een mening. De drie getallen die wij standaard dashboarden:

  • Hit ratio per cachelaag: onder de 90% voor productcontent betekent meestal dat de invalidatie te grof is.
  • Staleness: de tijd tussen een wijziging in het PIM en de zichtbaarheid op de site. Met event-gebaseerde invalidatie hoort dit onder de minuut te liggen.
  • Origin load: het aantal requests dat daadwerkelijk het PIM bereikt. Dit getal hoort vlak te blijven als het bezoek verdubbelt.

Conclusie

Goed cachen van PIM-data is geen kwestie van een TTL kiezen, maar van data classificeren naar houdbaarheid, invalideren op events in plaats van op de klok, stale data durven serveren terwijl je op de achtergrond ververst, en volatiele data naar een eigen laag verplaatsen. Het resultaat is een website die snel blijft onder piekbelasting, actueel blijft bij wijzigingen en overeind blijft als de bron hapert.

Productdata-integratie nodig?

Wij ontwerpen integratielagen die PIM-data snel en betrouwbaar ontsluiten in webshops en webapplicaties.

Neem contact op