Using plone.memoize.instance with several ZEO clients

You can use a shared cache instead--something like memcache or redis.

Here is a redis example:

from plone.memoize.ram import AbstractDict, choose_cache as base_choose_cache
class RedisAdapter(AbstractDict):

    def __init__(self, client, globalkey=''):
        self.client = client
        self.globalkey = globalkey and '%s:' % globalkey or ''

    def _make_key(self, source):
        if isinstance(source, unicode):
            source = source.encode('utf-8')
        return md5(source).hexdigest()

    def get_key(self, key):
        return self.globalkey + self._make_key(key)

    def __getitem__(self, key):
        cached_value = self.client.get(self.get_key(key))
        if cached_value is None:
            raise KeyError(key)
        else:
            return cPickle.loads(cached_value)

    def __setitem__(self, key, value):
        try:
            cached_value = cPickle.dumps(value)
            self.client.set(self.get_key(key), cached_value)
        except cPickle.PicklingError:
            pass


def get_client(fun_name=''):
    server = os.environ.get('REDIS_SERVER', None)
    if server is None:
        return base_choose_cache(fun_name)

    client = getattr(thread_local, "client", None)
    if client is None:
        server = os.environ.get("REDIS_SERVER", "127.0.0.1:6379")
        host, port = server.split(':')
        client = redis.StrictRedis(host=host, port=int(port), db=0)
        try:
            client.get('test-key')
            thread_local.client = client
        except redis.exceptions.ConnectionError:
            return base_choose_cache(fun_name)
    return RedisAdapter(client, fun_name)

directlyProvides(get_client, ICacheChooser)

Then, zcml registration

<utility component=".cache.get_client" provides="plone.memoize.interfaces.ICacheChooser" />

1 Like