def set_list(self, key, value, ttl=None, key_extractor=None): # locking it to prevent concurrency violation lock = self.lock(key) # check if item loaded v = self.get_list(key) if v[1]: self.unlock(lock) return v # packed: (value_metadata, value) if key_extractor is None: def key_extractor(x): return x["id"] try: value_metadata, value = value() if callable(value) else value item_keys = [] assert isinstance(value, collections.Iterable), "Value must be iterable" for item_value in value: item_key = create_cache_key(key.split(":")[0], key_extractor(item_value)) item_keys.append(item_key) self.set_item(item_key, item_value, ttl=ttl) self.redis.set(key, serialize((value_metadata, item_keys)), ex=ttl) return value_metadata, value finally: if lock: self.unlock(lock)
def hset_item(self, key, dict_key, value, ttl=None): old_item_key = self.redis.get(key) if old_item_key is None: # this is a new item # locking it to prevent concurrency violation lock = self.lock(key, nowait=True) if not lock: # it seems this item is loading in another thread # so, waiting for that: # wait & make sure the object is reloaded, the release the lock self.unlock(self.lock(key)) return self.hget_item(key, dict_key) # check if item loaded v = self.hget_item(key, dict_key, None) if v: self.unlock(lock) return v else: lock = None try: guid = uuid.uuid1() item_key = "%s:%s" % (key, guid) value = value() if callable(value) else value self.redis.hset(item_key, dict_key, serialize(value)) self.redis.expire(item_key, time=ttl) self.redis.set(key, item_key, ex=ttl) if old_item_key: self.redis.delete(old_item_key) return value finally: if lock: self.unlock(lock)