refactor: Update RedisCache to use AsyncInMemoryCache as fallback when Redis cache is not connected

This commit is contained in:
ogabrielluiz 2024-06-18 00:14:11 -03:00
commit 4b71295caf
3 changed files with 21 additions and 16 deletions

View file

@ -29,7 +29,7 @@ class CacheServiceFactory(ServiceFactory):
logger.debug("Redis cache is connected") logger.debug("Redis cache is connected")
return redis_cache return redis_cache
logger.warning("Redis cache is not connected, falling back to in-memory cache") logger.warning("Redis cache is not connected, falling back to in-memory cache")
return ThreadingInMemoryCache() return AsyncInMemoryCache()
elif settings_service.settings.cache_type == "memory": elif settings_service.settings.cache_type == "memory":
return ThreadingInMemoryCache() return ThreadingInMemoryCache()

View file

@ -243,10 +243,11 @@ class RedisCache(CacheService):
try: try:
self._client.ping() self._client.ping()
return True return True
except redis.exceptions.ConnectionError: except redis.exceptions.ConnectionError as exc:
logger.error(f"RedisCache could not connect to the Redis server: {exc}")
return False return False
def get(self, key): async def get(self, key, lock=None):
""" """
Retrieve an item from the cache. Retrieve an item from the cache.
@ -256,10 +257,12 @@ class RedisCache(CacheService):
Returns: Returns:
The value associated with the key, or None if the key is not found. The value associated with the key, or None if the key is not found.
""" """
value = self._client.get(key) if key is None:
return None
value = self._client.get(str(key))
return pickle.loads(value) if value else None return pickle.loads(value) if value else None
def set(self, key, value): async def set(self, key, value, lock=None):
""" """
Add an item to the cache. Add an item to the cache.
@ -269,13 +272,13 @@ class RedisCache(CacheService):
""" """
try: try:
if pickled := pickle.dumps(value): if pickled := pickle.dumps(value):
result = self._client.setex(key, self.expiration_time, pickled) result = self._client.setex(str(key), self.expiration_time, pickled)
if not result: if not result:
raise ValueError("RedisCache could not set the value.") raise ValueError("RedisCache could not set the value.")
except TypeError as exc: except TypeError as exc:
raise TypeError("RedisCache only accepts values that can be pickled. ") from exc raise TypeError("RedisCache only accepts values that can be pickled. ") from exc
def upsert(self, key, value): async def upsert(self, key, value, lock=None):
""" """
Inserts or updates a value in the cache. Inserts or updates a value in the cache.
If the existing value and the new value are both dictionaries, they are merged. If the existing value and the new value are both dictionaries, they are merged.
@ -284,14 +287,16 @@ class RedisCache(CacheService):
key: The key of the item. key: The key of the item.
value: The value to insert or update. value: The value to insert or update.
""" """
existing_value = self.get(key) if key is None:
return
existing_value = await self.get(key)
if existing_value is not None and isinstance(existing_value, dict) and isinstance(value, dict): if existing_value is not None and isinstance(existing_value, dict) and isinstance(value, dict):
existing_value.update(value) existing_value.update(value)
value = existing_value value = existing_value
self.set(key, value) await self.set(key, value)
def delete(self, key): async def delete(self, key, lock=None):
""" """
Remove an item from the cache. Remove an item from the cache.
@ -300,7 +305,7 @@ class RedisCache(CacheService):
""" """
self._client.delete(key) self._client.delete(key)
def clear(self): async def clear(self, lock=None):
""" """
Clear all items from the cache. Clear all items from the cache.
""" """
@ -308,17 +313,17 @@ class RedisCache(CacheService):
def __contains__(self, key): def __contains__(self, key):
"""Check if the key is in the cache.""" """Check if the key is in the cache."""
return False if key is None else self._client.exists(key) return False if key is None else self._client.exists(str(key))
def __getitem__(self, key): async def __getitem__(self, key):
"""Retrieve an item from the cache using the square bracket notation.""" """Retrieve an item from the cache using the square bracket notation."""
return self.get(key) return self.get(key)
def __setitem__(self, key, value): async def __setitem__(self, key, value):
"""Add an item to the cache using the square bracket notation.""" """Add an item to the cache using the square bracket notation."""
self.set(key, value) self.set(key, value)
def __delitem__(self, key): async def __delitem__(self, key):
"""Remove an item from the cache using the square bracket notation.""" """Remove an item from the cache using the square bracket notation."""
self.delete(key) self.delete(key)

View file

@ -23,7 +23,7 @@ class ChatService(Service):
"result": data, "result": data,
"type": type(data), "type": type(data),
} }
await self.cache_service.upsert(key, result_dict, lock=lock or self._cache_locks[key]) await self.cache_service.upsert(str(key), result_dict, lock=lock or self._cache_locks[key])
return key in self.cache_service return key in self.cache_service
async def get_cache(self, key: str, lock: Optional[asyncio.Lock] = None) -> Any: async def get_cache(self, key: str, lock: Optional[asyncio.Lock] = None) -> Any: