fix(caching): handle stale isolated Redis semantic index
This commit is contained in:
parent
3494871730
commit
8cb52ce0bb
@ -128,6 +128,9 @@ class RedisSemanticCache(BaseCache):
|
||||
redis_url: str,
|
||||
cache_vectorizer: Any,
|
||||
) -> Any:
|
||||
def _is_schema_mismatch(exc: ValueError) -> bool:
|
||||
return "schema does not match" in str(exc)
|
||||
|
||||
try:
|
||||
return semantic_cache_cls(
|
||||
name=index_name,
|
||||
@ -138,7 +141,7 @@ class RedisSemanticCache(BaseCache):
|
||||
overwrite=False,
|
||||
)
|
||||
except ValueError as exc:
|
||||
if "schema does not match" not in str(exc):
|
||||
if not _is_schema_mismatch(exc):
|
||||
raise
|
||||
|
||||
isolated_index_name = f"{index_name}_isolated"
|
||||
@ -146,14 +149,31 @@ class RedisSemanticCache(BaseCache):
|
||||
"Redis semantic-cache existing index schema is not isolated; "
|
||||
f"using isolated index - {isolated_index_name}"
|
||||
)
|
||||
return semantic_cache_cls(
|
||||
name=isolated_index_name,
|
||||
redis_url=redis_url,
|
||||
vectorizer=cache_vectorizer,
|
||||
distance_threshold=self.distance_threshold,
|
||||
filterable_fields=[self.CACHE_KEY_FILTERABLE_FIELD],
|
||||
overwrite=False,
|
||||
)
|
||||
try:
|
||||
return semantic_cache_cls(
|
||||
name=isolated_index_name,
|
||||
redis_url=redis_url,
|
||||
vectorizer=cache_vectorizer,
|
||||
distance_threshold=self.distance_threshold,
|
||||
filterable_fields=[self.CACHE_KEY_FILTERABLE_FIELD],
|
||||
overwrite=False,
|
||||
)
|
||||
except ValueError as isolated_exc:
|
||||
if not _is_schema_mismatch(isolated_exc):
|
||||
raise
|
||||
|
||||
print_verbose(
|
||||
"Redis semantic-cache isolated index schema is stale; "
|
||||
f"recreating isolated index - {isolated_index_name}"
|
||||
)
|
||||
return semantic_cache_cls(
|
||||
name=isolated_index_name,
|
||||
redis_url=redis_url,
|
||||
vectorizer=cache_vectorizer,
|
||||
distance_threshold=self.distance_threshold,
|
||||
filterable_fields=[self.CACHE_KEY_FILTERABLE_FIELD],
|
||||
overwrite=True,
|
||||
)
|
||||
|
||||
def _get_cache_filters(self, key: str) -> Dict[str, str]:
|
||||
return {self.CACHE_KEY_FIELD_NAME: str(key)}
|
||||
|
||||
@ -232,6 +232,79 @@ def test_redis_semantic_cache_uses_isolated_index_for_old_schema(monkeypatch):
|
||||
]
|
||||
|
||||
|
||||
def test_redis_semantic_cache_overwrites_stale_isolated_index(monkeypatch):
|
||||
fallback_cache_mock = MagicMock()
|
||||
semantic_cache_mock = MagicMock(
|
||||
side_effect=[
|
||||
ValueError("Existing index schema does not match"),
|
||||
ValueError("Existing index schema does not match"),
|
||||
fallback_cache_mock,
|
||||
]
|
||||
)
|
||||
custom_vectorizer_mock = MagicMock()
|
||||
|
||||
with patch.dict(
|
||||
"sys.modules",
|
||||
{
|
||||
"redisvl.extensions.llmcache": MagicMock(SemanticCache=semantic_cache_mock),
|
||||
"redisvl.utils.vectorize": MagicMock(
|
||||
CustomTextVectorizer=custom_vectorizer_mock
|
||||
),
|
||||
},
|
||||
):
|
||||
from litellm.caching.redis_semantic_cache import RedisSemanticCache
|
||||
|
||||
monkeypatch.setenv("REDIS_HOST", "localhost")
|
||||
monkeypatch.setenv("REDIS_PORT", "6379")
|
||||
monkeypatch.setenv("REDIS_PASSWORD", "test_password")
|
||||
|
||||
redis_semantic_cache = RedisSemanticCache(
|
||||
similarity_threshold=0.8,
|
||||
index_name="existing_index",
|
||||
)
|
||||
|
||||
assert redis_semantic_cache.llmcache is fallback_cache_mock
|
||||
assert (
|
||||
semantic_cache_mock.call_args_list[2].kwargs["name"]
|
||||
== "existing_index_isolated"
|
||||
)
|
||||
assert semantic_cache_mock.call_args_list[2].kwargs["overwrite"] is True
|
||||
assert semantic_cache_mock.call_args_list[2].kwargs["filterable_fields"] == [
|
||||
RedisSemanticCache.CACHE_KEY_FILTERABLE_FIELD
|
||||
]
|
||||
|
||||
|
||||
def test_redis_semantic_cache_reraises_unexpected_isolated_index_error(monkeypatch):
|
||||
semantic_cache_mock = MagicMock(
|
||||
side_effect=[
|
||||
ValueError("Existing index schema does not match"),
|
||||
ValueError("connection failed"),
|
||||
]
|
||||
)
|
||||
custom_vectorizer_mock = MagicMock()
|
||||
|
||||
with patch.dict(
|
||||
"sys.modules",
|
||||
{
|
||||
"redisvl.extensions.llmcache": MagicMock(SemanticCache=semantic_cache_mock),
|
||||
"redisvl.utils.vectorize": MagicMock(
|
||||
CustomTextVectorizer=custom_vectorizer_mock
|
||||
),
|
||||
},
|
||||
):
|
||||
from litellm.caching.redis_semantic_cache import RedisSemanticCache
|
||||
|
||||
monkeypatch.setenv("REDIS_HOST", "localhost")
|
||||
monkeypatch.setenv("REDIS_PORT", "6379")
|
||||
monkeypatch.setenv("REDIS_PASSWORD", "test_password")
|
||||
|
||||
with pytest.raises(ValueError, match="connection failed"):
|
||||
RedisSemanticCache(
|
||||
similarity_threshold=0.8,
|
||||
index_name="existing_index",
|
||||
)
|
||||
|
||||
|
||||
def test_redis_semantic_cache_reraises_unexpected_index_error():
|
||||
from litellm.caching.redis_semantic_cache import RedisSemanticCache
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user