🔨 chore(base.py): add upsert method to BaseCacheManager to provide a common interface for inserting or updating cache items
✨ feat(manager.py): add upsert method to InMemoryCache and RedisCache to support inserting or updating cache items 🐛 fix(manager.py): fix client_id generation in handle_websocket method to avoid overwriting existing cache items 🔨 chore(manager.py): refactor handle_websocket method to use upsert method and improve readability
This commit is contained in:
parent
20afabd90a
commit
e8d3a5df6d
3 changed files with 64 additions and 4 deletions
10
src/backend/langflow/services/cache/base.py
vendored
10
src/backend/langflow/services/cache/base.py
vendored
|
|
@ -32,6 +32,16 @@ class BaseCacheManager(abc.ABC, Service):
|
||||||
value: The value to cache.
|
value: The value to cache.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def upsert(self, key, value):
|
||||||
|
"""
|
||||||
|
Add an item to the cache if it doesn't exist, or update it if it does.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key: The key of the item.
|
||||||
|
value: The value to cache.
|
||||||
|
"""
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def delete(self, key):
|
def delete(self, key):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
41
src/backend/langflow/services/cache/manager.py
vendored
41
src/backend/langflow/services/cache/manager.py
vendored
|
|
@ -91,6 +91,27 @@ class InMemoryCache(BaseCacheManager):
|
||||||
self._cache.popitem(last=False)
|
self._cache.popitem(last=False)
|
||||||
self._cache[key] = {"value": value, "time": time.time()}
|
self._cache[key] = {"value": value, "time": time.time()}
|
||||||
|
|
||||||
|
def upsert(self, key, value):
|
||||||
|
"""
|
||||||
|
Inserts or updates a value in the cache.
|
||||||
|
If the existing value and the new value are both dictionaries, they are merged.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key: The key of the item.
|
||||||
|
value: The value to insert or update.
|
||||||
|
"""
|
||||||
|
with self._lock:
|
||||||
|
existing_value = self.get(key)
|
||||||
|
if (
|
||||||
|
existing_value is not None
|
||||||
|
and isinstance(existing_value, dict)
|
||||||
|
and isinstance(value, dict)
|
||||||
|
):
|
||||||
|
existing_value.update(value)
|
||||||
|
value = existing_value
|
||||||
|
|
||||||
|
self.set(key, value)
|
||||||
|
|
||||||
def get_or_set(self, key, value):
|
def get_or_set(self, key, value):
|
||||||
"""
|
"""
|
||||||
Retrieve an item from the cache. If the item does not exist, set it with the provided value.
|
Retrieve an item from the cache. If the item does not exist, set it with the provided value.
|
||||||
|
|
@ -220,6 +241,26 @@ class RedisCache(BaseCacheManager):
|
||||||
"""
|
"""
|
||||||
self._client.setex(key, self.expiration_time, pickle.dumps(value))
|
self._client.setex(key, self.expiration_time, pickle.dumps(value))
|
||||||
|
|
||||||
|
def upsert(self, key, value):
|
||||||
|
"""
|
||||||
|
Inserts or updates a value in the cache.
|
||||||
|
If the existing value and the new value are both dictionaries, they are merged.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key: The key of the item.
|
||||||
|
value: The value to insert or update.
|
||||||
|
"""
|
||||||
|
existing_value = self.get(key)
|
||||||
|
if (
|
||||||
|
existing_value is not None
|
||||||
|
and isinstance(existing_value, dict)
|
||||||
|
and isinstance(value, dict)
|
||||||
|
):
|
||||||
|
existing_value.update(value)
|
||||||
|
value = existing_value
|
||||||
|
|
||||||
|
self.set(key, value)
|
||||||
|
|
||||||
def delete(self, key):
|
def delete(self, key):
|
||||||
"""
|
"""
|
||||||
Remove an item from the cache.
|
Remove an item from the cache.
|
||||||
|
|
|
||||||
|
|
@ -175,8 +175,11 @@ class ChatManager(Service):
|
||||||
# client_id is the flow id but that already exists in the cache
|
# client_id is the flow id but that already exists in the cache
|
||||||
# so we need to change it to something else
|
# so we need to change it to something else
|
||||||
|
|
||||||
client_id = f"{client_id}_chat" if "_chat" not in client_id else client_id
|
result_dict = {
|
||||||
self.cache_manager.set(client_id, langchain_object)
|
"result": langchain_object.result,
|
||||||
|
"type": type(langchain_object),
|
||||||
|
}
|
||||||
|
self.cache_manager.upsert(client_id, result_dict)
|
||||||
return client_id in self.cache_manager
|
return client_id in self.cache_manager
|
||||||
|
|
||||||
async def handle_websocket(self, client_id: str, websocket: WebSocket):
|
async def handle_websocket(self, client_id: str, websocket: WebSocket):
|
||||||
|
|
@ -199,9 +202,15 @@ class ChatManager(Service):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
with self.chat_cache.set_client_id(client_id):
|
with self.chat_cache.set_client_id(client_id):
|
||||||
langchain_object = self.cache_manager.get(f"{client_id}_chat")
|
if langchain_object := self.cache_manager.get(client_id).get(
|
||||||
|
"result"
|
||||||
|
):
|
||||||
await self.process_message(client_id, payload, langchain_object)
|
await self.process_message(client_id, payload, langchain_object)
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Could not find a LangChain object for client_id {client_id}"
|
||||||
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
# Handle any exceptions that might occur
|
# Handle any exceptions that might occur
|
||||||
logger.error(f"Error handling websocket: {exc}")
|
logger.error(f"Error handling websocket: {exc}")
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue