Skip to content

Instantly share code, notes, and snippets.

@nmante
Last active May 3, 2018 10:51
Show Gist options
  • Save nmante/9ab5507b819e5cd3064d58c1bf3f0d4f to your computer and use it in GitHub Desktop.
Save nmante/9ab5507b819e5cd3064d58c1bf3f0d4f to your computer and use it in GitHub Desktop.
Caching Example
class BaseCache(object):
def load(self, key, **kwargs):
raise NotImplementedError
def write(self, key, record, **kwargs):
raise NotImplementedError
def delete(self, key, **kwargs):
raise NotImplementedError
from repositories.base import BaseRepository
from caches.base import BaseCache
from caches.redis_cache import RedisCache
class CacheRepository(BaseRepository):
def __init__(self, prepend_key, cache=None, **kwargs):
assert isinstance(prepend_key, str)
if cache:
assert isinstance(cache, BaseCache)
self._cache = cache if cache else RedisCache(**kwargs)
self._prepend_key = prepend_key
super().__init__()
def _build_key(self, id):
assert id is not None
return '{}:{}'.format(self._prepend_key, id)
def read(self, id, **kwargs):
key = self._build_key(id)
record = self._cache.load(key, **kwargs)
if record is not None:
return record
try:
record = super().read(id)
except Exception as e:
print('{}: Failed to "read". ID:{}'.format(self.name, id))
return
return self._cache.write(key, record, **kwargs)
def create(self, data, **kwargs):
try:
record = super().create(data)
except Exception as e:
print('{}: Failed to "create". DATA:{}'.format(self.name, data))
return
key = self._build_key(record['id'])
return self._cache.write(key, record, **kwargs)
def update(self, id, data, **kwargs):
try:
record = super().update(data)
except Exception as e:
print('{}: Failed to "update". ID:{}'.format(self.name, id))
return
key = self._build_key(id)
return self._cache.write(key, record, **kwargs)
def delete(self, id):
try:
record_id = super().delete(id)
except Exception as e:
print('{}: Failed to "delete". ID:{}'.format(self.name, id))
return
key = self._build_key(record_id)
self._cache.delete(key)
return record_id
def __str__(self):
super_str = super().__str__()
cache_info = self._cache.__str__()
return '{}\n{}'.format(cache_info, super_str)
@property
def name(self):
return self.__class__.__name__
#!/usr/bin/env python3
import redis
from repositories.base import BaseRepository
from repositories.cache import CacheRepository
def main():
repo = BaseRepository()
repo.read('a')
random_cache = CacheRepository('random', host='localhost', port=6379, db=0)
hello = random_cache.create({'hello': 1})
world = random_cache.create({'world': 20})
user_cache = CacheRepository('users')
nii = user_cache.create({
'name': 'Nii Mante'
})
kendyl = user_cache.create({
'name': 'Kendyl Johnson'
})
user_cache.delete(10)
print('Fetched Kendyl {}'.format(user_cache.read(kendyl['id'])))
print(user_cache)
user_cache.delete(kendyl['id'])
if __name__ == "__main__":
main()
import json
import random
import redis
from caches.base import BaseCache
class RedisCache(BaseCache):
def __init__(self, **kwargs):
random.seed()
self._cache = redis.StrictRedis(**kwargs)
self._ttl = kwargs.get('ttl', 20)
def _ttl_with_jitter(self):
return int(self._ttl * (1 + .2*random.random()))
def load(self, key, **kwargs):
raw_record = self._cache.get(key)
if raw_record is None:
return None
try:
decoded_record = raw_record.decode('utf-8').replace("'", '"')
except Exception as e:
print('{}: Error utf-8 decoding record for key = {}'.format(self.name, key))
return None
try:
record = json.loads(decoded_record)
except json.decoder.JSONDecodeError as je:
print('{}: Error JSON decoding record for key = {}'.format(self.name, key))
return None
return record
def write(self, key, record, **kwargs):
_ttl = ttl if kwargs.get('ttl') else self._ttl_with_jitter()
if record is None:
return None
is_inserted = self._cache.setex(key, _ttl, record)
if is_inserted:
print('{}: INSERT -- RECORD = {} with KEY = {} for TTL = {} into redis {}'.format(
self.__class__.__name__, record, key, _ttl, self._cache))
else:
print('{}: SKIPPING INSERT -- RECORD = {} with KEY = {} for TTL = {} into redis {}'.format(
self.__class__.__name__, record, key, _ttl, self._cache))
return record
def delete(self, key, **kwargs):
num_records_removed = self._cache.delete(key)
if num_records_removed > 0:
print(
'{}: DELETE -- {} records with key:{} from redis:{}'
.format(self.__class__.__name__, num_records_removed, key, self._cache))
else:
print(
'{}: SKIPPING DELETE -- {} records with key:{} from redis:{}'
.format(self.__class__.__name__, num_records_removed, key, self._cache))
return num_records_removed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment