Mar 04

At work we have over 200 modules and Mason components that use
CHI to cache some data or HTML. Each has its own
distinct namespace to prevent collisions.

Each namespace uses one of several different storage types — memcached, local file, NFS
file – depending on its usage characteristics. Each storage type has a set of default
parameters (e.g. root_dir for file) that rarely change. Finally, there are some defaults
we want to use across all of our caches.

To maintain a coherent cache strategy — and our sanity — we need a single place to
see and adjust all this configuration.

So instead of repeatedly embedding parameters like this:

my $cache = CHI->new
   (namespace => 'Foo', driver => 'File', root_dir => '/path/to/root',
    depth => 3, expires_in => '15m', expires_variance => 0.2);

...

my $cache = CHI->new
   (namespace => 'Bar', driver => 'Memcached',
    servers => [ "10.0.0.15:11211", "10.0.0.17:11211" ],
    compress_threshold => 10_000, expires_in => '1h', expires_variance => 0.2);

we can do this:

my $cache = CHI->new(namespace => 'Foo');

...

my $cache = CHI->new(namespace => 'Bar');

then in a YAML configuration file:

defaults:
  expires_variance: 0.2

storage:
  local_file:
    driver: File
    root_dir: /path/to/local/root
  nfs_file:
    driver: File
    root_dir: /path/to/nfs/root
  memcached:
    driver: Memcached
    servers: [ ... ]
    compress_threshold: 10_000

namespace:
  Foo: { storage: local_file, expires_in: 15m }
  Bar: { storage: memcached,  expires_in: 1h }
  Baz: { storage: memcached,  expires_in: 2h }
  ...

In the first paragraph we define overall defaults. In the second we define a set of
storage types, each with their own defaults. In the third we assign each namespace to a
storage type and an expiration time. Each level can override the defaults of previous
levels, and arguments passed in CHI->new override anything in configuration.

Support for this kind of configuration is available as of CHI 0.52. You should first
create a CHI subclass for your application, so as not to interfere with other CHI users in
the same process:

package My::CHI;
use base qw(CHI);

Then specify configuration with a hash or file:

My::CHI->config({ storage => ..., namespace => ..., defaults => ... });

My::CHI->config(YAML::XS::LoadFile("/path/to/cache.yml"));

Even if you don’t have 200 namespaces, it’s nice to have a single place where you can
fiddle with cache controls.

Leave a Reply

preload preload preload