[Solved] Caching probleem in Drupal 8 met TCPDF

Drupal 8 cache

[Solved] Caching probleem in Drupal 8 met TCPDF

Voor één van onze klanten hebben we een headless Drupal 8 opgezet die PDF's genereert met de TCPDF library, maar al snel werd duidelijk dat er iets grondig mis liep met de Drupal core caching bij het gebruiken van deze library.

Probleemstelling

Tijdens het ontwikkelen van de website, wanneer alle caching was uitgeschakeld, liep alles perfect. Toen we in samenspraak met de klant de website online te plaatsen liepen we al snel tegen een groot probleem op: geen enkele pagina werd gecached. Na het bekijken van de headers bleek dat de X-Drupal-Cache en X-Drupal-Dynamic-Cache headers niet aanwezig waren.


Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:*
Cache-Control:must-revalidate, no-cache, private
Connection:Keep-Alive
Content-Encoding:gzip
Content-language:nl
Content-Type:text/html; charset=UTF-8
Date:Thu, 05 Jan 2017 07:55:49 GMT
Expires:Sun, 19 Nov 1978 05:00:00 GMT
Keep-Alive:timeout=15, max=100
Server:Apache
Transfer-Encoding:chunked
Vary:Accept-Encoding
X-Content-Type-Options:nosniff
X-Frame-Options:SAMEORIGIN
X-Generator:Drupal 8 (https://www.drupal.org)
X-Robots-Tag:noindex, noarchive, follow
X-UA-Compatible:IE=edge

We besloten om in de code van Drupal core te duiken en uit te zoeken waar deze headers werden toegevoegd. Al snel werd het duidelijk dat dit in de page_cache module werd gedaan. Meer bepaald in de functie fetch() in de class Drupal\page_cache\StackMiddleware\PageCache. Deze functie gaat een response uit de backend halen en deze opslaan in de cache, indien mogelijk.

Om de pagina te cachen, moet de response aan verschillende voorwaarden voldoen. Eén van deze voorwaarden is dat er geen "policies" de pagina ervan weerhouden om gecached te worden:


// Allow policy rules to further restrict which responses to cache.
if ($this->responsePolicy->check($response, $request) === ResponsePolicyInterface::DENY) {
  return $response;
}

Na wat verder debuggen en zoeken, werd duidelijk dat al onze responses "ge-restricted" werden en dus aan bovenstaande conditie voldeden met als gevolg dat er niets werd gecached. 

Oorzaak

De volgende stap was om de oorzaak van deze restrictie vast te stellen. De boosdoener bleek de "KillSwitch" policy te zijn. Deze policy kan worden aangeroepen als er niets op de pagina mag gecached worden. Dit wordt bijvoorbeeld gedaan als de maintenance page wordt afgebeeld (deze komt dus nooit uit cache), maar ook als er een pagina wordt geladen met een Drupal message. De functie drupel_set_message bevat volgende code:


function drupal_set_message($message = NULL, $type = 'status', $repeat = FALSE) {
  ...
  if (isset($message)) {
    ...
    // Mark this page as being uncacheable.
    \Drupal::service('page_cache_kill_switch')->trigger();
  }
  ... 
 }

Het vreemde was dat er geen Drupal messages zichtbaar waren, maar toch werd deze functie opgeroepen met een notice vanuit de TCPDF library. Deze notice werd opgeroepen op elke pagina waardoor er dus niets werd gecached.

Oplossing

De oplossing voor het hele caching probleem hebben we dus simpel opgelost door de TCPDF notice te patchen waardoor de functie drupal_set_message niet meer werd opgeroepen. Na het opnieuw controleren van de headers, werkte alles zoals verwacht:


X-Drupal-Cache:HIT
X-Drupal-Dynamic-Cache:MISS

Blijf op de hoogte via onze nieuwsbrief