Invalidate the page cache according to a duration with Drupal 8

Time

For some purposes it may be necessary to have content, or content elements, that may vary according to a certain time period, and therefore require a cache invalidation according to a certain duration. This is for example the typical case of a list of future and/or past events, which must invariably change over time.

Drupal 8 has three cache systems:

  • Cache Tag: which allow us to invalidate pages, or page elements, according to specific tags collected and automatically uploaded to each page
  • Cache context: which allow us to vary the cache according to different contexts (by URL, language, cookie, permissions, etc.)
  • Cache max-age cache: which allows us to specify a fixed duration for the validity of the cache set up

The max-age cache seems to meet all our needs, namely to define a fixed duration at the end of which the cache will be automatically invalidated. Unfortunately, this cache system does not yet work perfectly in all situations, and some max-age caches may not be collected and put back into the page headers in some situations. An issue is open on this subject, Bubbling of elements' max-age to the page's headers and the page cache, and also mentions the use of a contributed module Cache control override to fix this issue for certain situations.

Nevertheless, until these difficulties are resolved, we can have an already operational and remarkably effective solution, namely cache tags. Indeed, if Drupal automatically provides their tag caches for any entity, whether configuration or content, and takes care of collecting and invalidating them automatically, nothing prevents us from providing our own tag caches, reusable at will.

So, for example, instead of specifying a max-age cache of 3600 (to stipulate a cache validity period of 1 hour) for some content elements or pages of our project, we can very well add our own cache tag [time:hourly], or even [time:daily] or [time:weekly] to the cache tags. Anyway, I think you must have understood the concept.

Of course, adding these custom tag caches will have absolutely no effect on the invalidation of your project's cache, as long as you do not set up the logic of invalidation of these tag caches. This can be done in a few lines by implementing hook_cron().

use Drupal\Core\Cache\Cache;

/**
 * Implements hook_cron().
 */
function my_module_cron() {
  $request_time = \Drupal::time()->getCurrentTime();
  $state_service = \Drupal::state();
  $next_hourly_cron = $state_service->get('my_module.cache_cron_hourly', 0);
  if($next_hourly_cron < $request_time){
    $next_hour = strtotime(date('H') . ":59");
    $state_service->set('my_module.cache_cron_hourly',$next_hour);
    Cache::invalidateTags(['time:hourly']);
  }
  $next_daily_cron = $state_service->get('my_module.cache_cron_daily', 0);
  if ($next_daily_cron < $request_time) {
    $tomorrow = strtotime('tomorrow 0:59:00');
    $state_service->set('my_module.cache_cron_daily', $tomorrow);
    Cache::invalidateTags(['time:daily']);
  }
  $next_weekly_cron = $state_service->get('my_module.cache_cron_weekly', 0);
  if($next_weekly_cron < $request_time){
    $next_week = strtotime('next monday 0:59:00');
    $state_service->set('my_module.cache_cron_weekly',$next_week);
    Cache::invalidateTags(['time:weekly']);
  }
}

And so, of course, with a scheduled task (cron) that you have previously configured on your server (recommended) or at the project level (with the help of a Drupal freelancer of course) to be launched every hour (or less if necessary), you have a cache invalidation system remarkably effective based on a duration, whether for static cache of anonymous visitors or dynamic cache. Of course, all the variations (over time periods, or any other criteria finally) can be imagined here.

 

Ajouter un commentaire