Drupal has a robust and dynamic cache system that allows complex pages to have different parts of it cached in different ways.
Having a cache means that Drupal doesn't need to go back to the database and ask all the elements of the page to re-render everything for every page request. The results of the render can be stored in a cache and served much faster than having to recreate them again.
You might have a page that displays content from a node and contains a few blocks to show menus, search forms, share links, and similar. Each part of this page can be cached in different ways and all of this information bubbles up to the aggregate page cache.
Tracking down issues in the cache system can be a complex task. If one element on your page is not caching correctly then this can cause the whole page (and sometimes the entire site) to not be cached properly.
Solving these problems is very important but can be a time consuming process. The best place to start is by turning on debugging headers and looking to see what sort of cache tags are being generated. Performance analysis will tell you where the most database reads are coming from, which is usually a good indication of poorly cached content.
This is where the Cache Review module comes in. The module has been designed to decorate the outgoing page request and add lots of cache information to the page.
It's never to be used in production as it does create a lot of output on the page (even for anonymous users) but it is a very useful tool in getting to grips with what your cache is doing.
Installing Cache Review
Before you can add the Cache Review module to your codebase you need to set the "minimum-stability" setting in your composer.json file to "dev".
This module is quite rightly labelled as a development module and you need to allow composer to install a module in this state.
With that done you can require the Cache Review module like this.
composer require --dev drupal/cache_review
This is installed as a dev dependency just in case the change to composer was committed to git.
With the module in the codebase it's just a case of enabling it. You can do this through the administration interface or via Drush using the following command.
drush en cache_review
The module has no configuration or setup, so it is ready to use once installed.
Using Cache Review
After enabling this module it will automatically add cache information to non-administration pages. This essentially means that the entire front end of your site will contain lots of information about what the cache is doing.
Information regarding the cache is injected into every element on the page along with a synopsis of the overall cache at the top of the page.
Here is this site with the cache review module turned on.
This does look a bit messy, but it is trying to convey a lot of information all at once. The most important part of this information are the letters placed around the page.
The letters have important meaning with regards to the current state of the cache.
- C - Item cached separately. This essentially means that the item is cached in a separate cache bucket from the central cache system, but is still being cached in some way.
- L - From Lazy builder. Meaning that the cache is being generated through the lazy builder interfaces.
- N - Normal item cache properties. Which means that the cache "tags", "contexts" and/or "max-age" settings are being used to control the cache of this item.
If the letter C or N is shown in red this means that the cache of that element is not being cached correctly. Well, actually it means that the auto_placeholder_conditions do not match the auto_placeholder_conditions of the page, but this essentially means that the cache is not validated for the context of that page request.
By hovering over each of the letters within the page you can get more information about what the cache is doing at that point in the page.
Here is an example of inspecting the cache of the breadcrumb element on a page of content.
The screenshot shows that the cache has a context of "url.path.parent", "url.path.is_front" and "url". This also shows that the maximum age of the cache is permanent (Drupal stores this information as -1).
Also at the top of the page is the result of the cache headers that the page produces. Depending on what you have enabled in your site this will show you your In Page Cache (IPC) or the Dynamic Page Cache (DPC).
IPC response status 'X-Drupal-Cache': HIT DPC response status 'X-Drupal-Dynamic-Cache': MISS
As a minimum, you should be looking to "HIT" the IPC cache on the second page load. Why the second page load and not the first? That is because on the first page load there might be no cache for that page and so the IPC will report a "MISS". After the second page load the cache has been warmed and the IPC should then report a "HIT". If the IPC reports a "MISS" every page load then something is wrong with your cache.
In order to get the DPC cache to read "HIT" you need to ensure that all the cache elements on your page do not align with the auto_placeholder_conditions setup in your site. On most sites that display content to users this is generally a difficult cache ideal to achieve, but is possible with careful configuration.
As a test (not of the module, but of Drupal itself) I wanted to turn off the cache for an element on the page and show how this bubbles up to the top of the page and disables the entire page cache. To this end I added the following "max-age" setting to a render array within the page.
$build['element']['#cache'] = ['max-age' => 0];
This disables the cache by setting the maximum amount of time that the element can be stored for to 0 seconds. I then inspected the cache of the page using the Cache Review module.
Here is the result.
As the inner element of the page can't be cached it means that this cache information bubbles up to the page level cache and invalidates the entire page cache.
In fact, in this situation the IPC and DPC headers at the top of the page read as follows.
IPC response status 'X-Drupal-Cache': HIT DPC response status 'X-Drupal-Dynamic-Cache': UNCACHEABLE
Finally, as a demonstration of how the Drupal cache system works there are a number of demo routes set up in the module. With the module installed you can visit the path at /cache-review to see a list of the cache demo pages available.
These pages are as follows.
- Cached page with max-age for items - Found at /cache-review/cached-max-age this page shows that setting a "max-age" will allow the page to cache and demonstrates how this value bubbles up the page.
- Uncacheable page, has lazy, some items cached due to keys. Found at /cache-review/uncacheable-lazy-keys shows a poor use of a lazy builder that causes the dynamic cache to be missed on every page load.
- Cached page with lazy items. Found at /cache-review/cached-lazy, and shows a better use of lazy builders that allow the entire page to be cached.
Using these pages you can demonstrate how different cache setups can cause the cache of a site to not work quite as expected.
The Cache Review module is a great tool for inspecting your sites cache setup. It will easily show you any problems with any item on your page and show clearly when those problems are solved.
It's also a really good learning tool for learning how the cache system works. Understanding what influences the cache and how that cache is bubbled to the top of the page are key to understanding how the cache system works. The demo pages that come with the module are really useful in showing how cache information added to the render array of a controller or block can change the cache of entire page.
Do NOT, whatever you do, deploy this module to production. If it accidentally gets enabled it on will trash your front end theme and cause your users some headaches. This module is only for local development, debugging and learning. You have been warned!
The module could use one or two accessibility tweaks. Relying on colours to convey the cache information will be a problem for certain developers. Having an accessible mode that can be configured might be a good idea for an improvement to the module.
The module can also have a few problems with the Big Pipe module, which is understandable as Big Pipe is intended to bypass cache settings.
Thanks Oleg Sabadash for this useful module!