Skip to content

Instantly share code, notes, and snippets.

@ostcar
Created October 13, 2015 06:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ostcar/b42dbe11a13ac0e7f88e to your computer and use it in GitHub Desktop.
Save ostcar/b42dbe11a13ac0e7f88e to your computer and use it in GitHub Desktop.
redis get_or_set
class RedisCache(_RedisCache):
"""
Wrapper to redis cache that creates status keys for the time a value is
created.
Idea from https://github.com/funkybob/puppy
"""
def get_or_set(self, key, callback, timeout=None, update_time=6):
"""
Get a key if it exists. Creates it if other case.
Sets a status key for the time the value is created, so other workers
do not created the same content in the meantime.
"""
# If redis is disabled, then we can call the callback immediately
if not settings.USE_REDIS_CACHE:
return callback()
redis = self.client.get_client()
# Key and status key
key = self.make_key(key)
state_key = key + ':status'
# Get the value
value = redis.get(key)
while value is None:
# Try to gain an updating lock
if redis.set(state_key, 'updating', ex=update_time, nx=True):
try:
# TODO: log how long callback needs. If it needs more then
# update_time, it should write a warning.
value = self.client.encode(callback())
# Resolve our timeout value
if timeout is None:
timeout = self.default_timeout
# Set the value
redis.set(key, value, ex=timeout)
finally:
# If the key is deleted it can not be recreated before the
# state_key expires. So the state_key has to be deleted.
redis.delete(state_key)
# Someone else is already updating the key, but we don't have a value
# to return, so we have to wait
else:
sleep(0.1)
value = redis.get(key)
try:
return self.client.decode(value)
except:
# If value can not be decoded, then delete it from the cache
redis.delete(key)
raise
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment