Switch Quay to using an in-container memcached for data model caching
This commit is contained in:
parent
5cecc54bd5
commit
ab0172d2fd
14 changed files with 246 additions and 65 deletions
73
data/cache/__init__.py
vendored
73
data/cache/__init__.py
vendored
|
@ -1,62 +1,23 @@
|
|||
import logging
|
||||
from data.cache.impl import NoopDataModelCache, InMemoryDataModelCache, MemcachedModelCache
|
||||
|
||||
from datetime import datetime
|
||||
def get_model_cache(config):
|
||||
""" Returns a data model cache matching the given configuration. """
|
||||
cache_config = config.get('DATA_MODEL_CACHE_CONFIG', {})
|
||||
engine = cache_config.get('engine', 'noop')
|
||||
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from six import add_metaclass
|
||||
if engine == 'noop':
|
||||
return NoopDataModelCache()
|
||||
|
||||
from util.expiresdict import ExpiresDict
|
||||
from util.timedeltastring import convert_to_timedelta
|
||||
if engine == 'inmemory':
|
||||
return InMemoryDataModelCache()
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
if engine == 'memcached':
|
||||
endpoint = cache_config.get('endpoint', None)
|
||||
if endpoint is None:
|
||||
raise Exception('Missing `endpoint` for memcached model cache configuration')
|
||||
|
||||
def is_not_none(value):
|
||||
return value is not None
|
||||
timeout = cache_config.get('timeout')
|
||||
connect_timeout = cache_config.get('connect_timeout')
|
||||
return MemcachedModelCache(endpoint, timeout=timeout, connect_timeout=connect_timeout)
|
||||
|
||||
|
||||
@add_metaclass(ABCMeta)
|
||||
class DataModelCache(object):
|
||||
""" Defines an interface for cache storing and returning tuple data model objects. """
|
||||
|
||||
@abstractmethod
|
||||
def retrieve(self, cache_key, loader, should_cache=is_not_none):
|
||||
""" Checks the cache for the specified cache key and returns the value found (if any). If none
|
||||
found, the loader is called to get a result and populate the cache.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class NoopDataModelCache(DataModelCache):
|
||||
""" Implementation of the data model cache which does nothing. """
|
||||
|
||||
def retrieve(self, cache_key, loader, should_cache=is_not_none):
|
||||
return loader()
|
||||
|
||||
|
||||
class InMemoryDataModelCache(DataModelCache):
|
||||
""" Implementation of the data model cache backed by an in-memory dictionary. """
|
||||
def __init__(self):
|
||||
self.cache = ExpiresDict(rebuilder=lambda: {})
|
||||
|
||||
def retrieve(self, cache_key, loader, should_cache=is_not_none):
|
||||
not_found = [None]
|
||||
logger.debug('Checking cache for key %s', cache_key.key)
|
||||
result = self.cache.get(cache_key.key, default_value=not_found)
|
||||
if result != not_found:
|
||||
logger.debug('Found result in cache for key %s: %s', cache_key.key, result)
|
||||
return result
|
||||
|
||||
logger.debug('Found no result in cache for key %s; calling loader', cache_key.key)
|
||||
result = loader()
|
||||
logger.debug('Got loaded result for key %s: %s', cache_key.key, result)
|
||||
if should_cache(result):
|
||||
logger.debug('Caching loaded result for key %s with expiration %s: %s', cache_key.key,
|
||||
result, cache_key.expiration)
|
||||
expires = convert_to_timedelta(cache_key.expiration) + datetime.now()
|
||||
self.cache.set(cache_key.key, result, expires=expires)
|
||||
logger.debug('Cached loaded result for key %s with expiration %s: %s', cache_key.key,
|
||||
result, cache_key.expiration)
|
||||
else:
|
||||
logger.debug('Not caching loaded result for key %s: %s', cache_key.key, result)
|
||||
|
||||
return result
|
||||
raise Exception('Unknown model cache engine `%s`' % engine)
|
||||
|
|
Reference in a new issue