Custom dispatcher invalidation rules

Most web sites use different approaches of caching to improve their performance, some within the application and some on the delivery side of the site, such as a content delivery network (CDN) or a simple reverse proxy like squid or varnish. Of course all of these can also be used together with CQ5, the default caching approach on the delivery side of CQ5 is the dispatcher.

The dispatcher is a pretty straight-forward cache, which has some built-in rules for invalidation. The most important rule is: Whenever a page is invalidated, all pages, which are located deeper in the content hierarchy below this page, are invalidated as well.

Some background: This might be based on the assumption, that a change on any page can influence the appearance of pages higher in the hierarchy; you should think of a change of the page title, which must be reflected in the navigation items of all other pages in that area. Combined with the /statfileslevel parameter you should be able to deliver always a correctly rendered page and never outdated content. At the cost of the cache hit ratio in the dispatcher.

I already described the inner working of the dispatcher in an older article. Knowing these internals also give you some more options if you want to tune this. In the following I describe an approach, which allows you to implement custom invalidation rules. The caching and the delivery of the cached files doesn’t change, only the cache invalidation.

The basic idea is to replace the call to /dispatcher/invalidate.cache (which is the standard handler for cache invalidation) by a custom script, which runs the invalidation on the cache. This custom script is configured as target URL in the invalidation agent(s) and updates the “last modification date” of the statfile according to your requirement.

For example you can have this perl script, which should behave like the dispatcher invalidation logic:

/usr/bin/perl -w
use strict;
use CGI;
use File::Find;
use File::Touch;
my $cacheroot = "/opt/www/docroot";
my $q = CGI->new;
my $path = q->param("Handle");
my $invalidation_path = $cacheroot . $path;
File::Find::find({wanted => \&wanted}, $invalidation_path);
exit;

sub wanted {
  my $f = shift;
  if ($f =~ /\.stat/) {
    touch ($f);
  }
}

Configure this script as a CGI on “/dispatcher/custom.invalidation”, then configure your invalidation accordingly, and voila, you’re done. You run your custom invalidation script. If you don’t like the standard behaviour (obviously you don’t …), adjust the logic in the wanted procedure.