dogpile.cache / docs / build / usage.rst

Usage Guide


At the time of this writing, popular key/value servers include Memcached, Redis, and Riak. While these tools all have different usage focuses, they all have in common that the storage model is based on the retrieval of a value based on a key; as such, they are all potentially suitable for caching, particularly Memcached which is first and foremost designed for caching.

With a caching system in mind, dogpile.cache provides an interface to a particular Python API targeted at that system.

A dogpile.cache configuration consists of the following components:

  • A region, which is an instance of :class:`.CacheRegion`, and defines the configuration details for a particular cache backend. The :class:`.CacheRegion` can be considered the "front end" used by applications.
  • A backend, which is an instance of :class:`.CacheBackend`, describing how values are stored and retrieved from a backend. This interface specifies only :meth:`~.CacheBackend.get`, :meth:`~.CacheBackend.set` and :meth:`~.CacheBackend.delete`. The actual kind of :class:`.CacheBackend` in use for a particular :class:`.CacheRegion` is determined by the underlying Python API being used to talk to the cache, such as Pylibmc. The :class:`.CacheBackend` is instantiated behind the scenes and not directly accessed by applications under normal circumstances.
  • Value generation functions. These are user-defined functions that generate new values to be placed in the cache. While dogpile.cache offers the usual "set" approach of placing data into the cache, the usual mode of usage is to only instruct it to "get" a value, passing it a creation function which will be used to generate a new value if and only if one is needed. This "get-or-create" pattern is the entire key to the "Dogpile" system, which coordinates a single value creation operation among many concurrent get operations for a particular key, eliminating the issue of an expired value being redundantly re-generated by many workers simultaneously.

Rudimentary Usage

dogpile.cache includes a Pylibmc backend. A basic configuration looks like:

from dogpile.cache import make_region

region = make_region().configure(
    expiration_time = 3600,
    arguments = {

def load_user_info(user_id):
    return some_database.lookup_user_by_id(user_id)

Above, we create a :class:`.CacheRegion` using the :func:`.make_region` function, then apply the backend configuration via the :meth:`.CacheRegion.configure` method, which returns the region. The name of the backend is the only argument required by :meth:`.CacheRegion.configure` itself, in this case dogpile.cache.pylibmc. However, in this specific case, the pylibmc backend also requires that the URL of the memcached server be passed within the arguments dictionary.

The configuration is separated into two sections. Upon construction via :func:`.make_region`, the :class:`.CacheRegion` object is available, typically at module import time, for usage in decorating functions. Additional configuration details passed to :meth:`.CacheRegion.configure` are typically loaded from a configuration file and therefore not necessarily available until runtime, hence the two-step configurational process.

Key arguments passed to :meth:`.CacheRegion.configure` include expiration_time, which is the expiration time passed to the Dogpile lock, and arguments, which are arguments used directly by the backend - in this case we are using arguments that are passed directly to the pylibmc module.

Region Configuration

The :func:`.make_region` function currently calls the :class:`.CacheRegion` constructor directly.

One you have a :class:`.CacheRegion`, the :meth:`.CacheRegion.cache_on_arguments` method can be used to decorate functions, but the cache itself can't be used until :meth:`.CacheRegion.configure` is called. The interface for that method is as follows:

The :class:`.CacheRegion` can also be configured from a dictionary, using the :meth:`.CacheRegion.configure_from_config` method:

Using a Region

The :class:`.CacheRegion` object is our front-end interface to a cache. It includes the following methods:

Creating Backends

Backends are located using the setuptools entrypoint system. To make life easier for writers of ad-hoc backends, a helper function is included which registers any backend in the same way as if it were part of the existing sys.path.

For example, to create a backend called DictionaryBackend, we subclass :class:`.CacheBackend`:

from dogpile.cache.api import CacheBackend, NO_VALUE

class DictionaryBackend(CacheBackend):
    def __init__(self, arguments):
        self.cache = {}

    def get(self, key):
        return self.cache.get(key, NO_VALUE)

    def set(self, key, value):
        self.cache[key] = value

    def delete(self, key):

Then make sure the class is available underneath the entrypoint dogpile.cache. If we did this in a file, it would be in setup() as:

  dictionary = mypackage.mybackend:DictionaryBackend

Alternatively, if we want to register the plugin in the same process space without bothering to install anything, we can use register_backend:

from dogpile.cache import register_backend

register_backend("dictionary", "mypackage.mybackend", "DictionaryBackend")

Our new backend would be usable in a region like this:

from dogpile.cache import make_region

region = make_region("myregion")


data = region.set("somekey", "somevalue")

The values we receive for the backend here are instances of CachedValue. This is a tuple subclass of length two, of the form:

(payload, metadata)

Where "payload" is the thing being cached, and "metadata" is information we store in the cache - a dictionary which currently has just the "creation time" and a "version identifier" as key/values. If the cache backend requires serialization, pickle or similar can be used on the tuple - the "metadata" portion will always be a small and easily serializable Python structure.

Changing Backend Behavior

The :class:`.ProxyBackend` is a decorator class provided to easily augment existing backend behavior without having to extend the original class. Using a decorator class is also adventageous as it allows us to share the altered behavior between different backends.

Proxies are added to the :class:`.CacheRegion` object using the :meth:`.CacheRegion.configure` method. Only the overridden methods need to be specified and the real backend can be accessed with the self.proxied object from inside the :class:`.ProxyBackend`.

For example, a simple class to log all calls to .set() would look like this:

from dogpile.cache.proxy import ProxyBackend

import logging
log = logging.getLogger(__name__)

class LoggingProxy(ProxyBackend):
    def set(self, key, value):
        log.debug('Setting Cache Key: %s' % key)
        self.proxied.set(key, value)

:class:`.ProxyBackend` can be be configured to optionally take arguments (as long as the :meth:`.ProxyBackend.__init__` method is called properly, either directly or via super(). In the example below, the RetryDeleteProxy class accepts a retry_count parameter on initialization. In the event of an exception on delete(), it will retry this many times before returning:

from dogpile.cache.proxy import ProxyBackend

class RetryDeleteProxy(ProxyBackend):
    def __init__(self, retry_count=5):
        super(RetryDeleteProxy, self).__init__()
        self.retry_count = retry_count

    def delete(self, key):
        retries = self.retry_count
        while retries > 0:
            retries -= 1


The wrap parameter of the :meth:`.CacheRegion.configure` accepts a list which can contain any combination of instantiated proxy objects as well as uninstantiated proxy classes. Putting the two examples above together would look like this:

from dogpile.cache import make_region

retry_proxy = RetryDeleteProxy(5)

region = make_region().configure(
    expiration_time = 3600,
    arguments = {
    wrap = [ LoggingProxy, retry_proxy ]

In the above example, the LoggingProxy object would be instantated by the :class:`.CacheRegion` and applied to wrap requests on behalf of the retry_proxy instance; that proxy in turn wraps requests on behalf of the original dogpile.cache.pylibmc backend.