Skip to content

Commit 791bdbb

Browse files
committed
feat(cache): improve warning messages for async-only client usage
- Add concise warning messages when sync methods are called with async-only client - Implement warning flag to prevent log spam (show warning only once per session) - Add comprehensive test coverage for warning behavior - Improve developer experience by providing clear guidance on method usage The warnings now clearly indicate which async methods should be used instead of sync methods when EmbeddingsCache is initialized with only an async client. This helps prevent confusion when developers unintentionally use different Redis connections than expected.
1 parent 15fbbb9 commit 791bdbb

File tree

2 files changed

+117
-20
lines changed

2 files changed

+117
-20
lines changed

redisvl/extensions/cache/embeddings/embeddings.py

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
class EmbeddingsCache(BaseCache):
1515
"""Embeddings Cache for storing embedding vectors with exact key matching."""
1616

17+
_warning_shown: bool = False # Class-level flag to prevent warning spam
18+
1719
def __init__(
1820
self,
1921
name: str = "embedcache",
@@ -168,11 +170,12 @@ def get_by_key(self, key: str) -> Optional[Dict[str, Any]]:
168170
embedding_data = cache.get_by_key("embedcache:1234567890abcdef")
169171
"""
170172
if self._owns_redis_client is False and self._redis_client is None:
171-
logger.warning(
172-
"You are using redis_client but you had initialised the EmbeddingCache with an async_redis_client only. "
173-
"If you intended to use async_redis_client, please use async aget(text, model_name) method of EmbeddingCache instead "
174-
"of get(text, model_name)."
175-
)
173+
if not EmbeddingsCache._warning_shown:
174+
logger.warning(
175+
"EmbeddingsCache initialized with async_redis_client only. "
176+
"Use async methods (aget_by_key) instead of sync methods (get_by_key)."
177+
)
178+
EmbeddingsCache._warning_shown = True
176179

177180
client = self._get_redis_client()
178181

@@ -210,11 +213,12 @@ def mget_by_keys(self, keys: List[str]) -> List[Optional[Dict[str, Any]]]:
210213
return []
211214

212215
if self._owns_redis_client is False and self._redis_client is None:
213-
logger.warning(
214-
"You are using redis_client but you had initialised the EmbeddingCache with an async_redis_client only. "
215-
"If you intended to use async_redis_client, please use async amget(texts, model_name) method of EmbeddingCache instead "
216-
"of mget(texts, model_name)."
217-
)
216+
if not EmbeddingsCache._warning_shown:
217+
logger.warning(
218+
"EmbeddingsCache initialized with async_redis_client only. "
219+
"Use async methods (amget_by_keys) instead of sync methods (mget_by_keys)."
220+
)
221+
EmbeddingsCache._warning_shown = True
218222

219223
client = self._get_redis_client()
220224

@@ -298,11 +302,12 @@ def set(
298302
)
299303

300304
if self._owns_redis_client is False and self._redis_client is None:
301-
logger.warning(
302-
"You are using redis_client but you had initialised the EmbeddingCache with an async_redis_client only. "
303-
"If you intended to use async_redis_client, please use async aset(text, model_name, embedding, metadata=None, ttl=None) "
304-
"method of EmbeddingCache instead of set(text, model_name, embedding, metadata=None, ttl=None)."
305-
)
305+
if not EmbeddingsCache._warning_shown:
306+
logger.warning(
307+
"EmbeddingsCache initialized with async_redis_client only. "
308+
"Use async methods (aset) instead of sync methods (set)."
309+
)
310+
EmbeddingsCache._warning_shown = True
306311

307312
# Store in Redis
308313
client = self._get_redis_client()
@@ -355,11 +360,12 @@ def mset(
355360
return []
356361

357362
if self._owns_redis_client is False and self._redis_client is None:
358-
logger.warning(
359-
"You are using redis_client but you had initialised the EmbeddingCache with an async_redis_client only. "
360-
"If you intended to use async_redis_client, please use async amset(items, ttl=None) method of EmbeddingCache instead "
361-
"of mset(items, ttl=None)."
362-
)
363+
if not EmbeddingsCache._warning_shown:
364+
logger.warning(
365+
"EmbeddingsCache initialized with async_redis_client only. "
366+
"Use async methods (amset) instead of sync methods (mset)."
367+
)
368+
EmbeddingsCache._warning_shown = True
363369

364370
client = self._get_redis_client()
365371
keys = []
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Test warning behavior when using sync methods with async-only client."""
2+
3+
import asyncio
4+
import logging
5+
from unittest.mock import patch
6+
7+
import pytest
8+
from redis import Redis
9+
10+
from redisvl.extensions.cache.embeddings import EmbeddingsCache
11+
from redisvl.redis.connection import RedisConnectionFactory
12+
13+
14+
def test_sync_methods_warn_with_async_only_client(caplog):
15+
"""Test that sync methods warn when only async client is provided."""
16+
# Reset the warning flag for testing
17+
EmbeddingsCache._warning_shown = False
18+
19+
# Create async redis client
20+
async_client = RedisConnectionFactory.get_async_redis_connection(
21+
"redis://localhost:6379"
22+
)
23+
24+
# Initialize EmbeddingsCache with only async_redis_client
25+
cache = EmbeddingsCache(name="test_cache", async_redis_client=async_client)
26+
27+
# Capture log warnings
28+
with caplog.at_level(logging.WARNING):
29+
# First sync method call should warn
30+
_ = cache.get_by_key("test_key")
31+
32+
# Check warning was logged
33+
assert len(caplog.records) == 1
34+
assert "initialized with async_redis_client only" in caplog.records[0].message
35+
assert "Use async methods" in caplog.records[0].message
36+
37+
# Clear captured logs
38+
caplog.clear()
39+
40+
# Second sync method call should NOT warn (flag prevents spam)
41+
_ = cache.set(text="test", model_name="model", embedding=[0.1, 0.2])
42+
43+
# Should not have logged another warning
44+
assert len(caplog.records) == 0
45+
46+
47+
def test_no_warning_with_sync_client():
48+
"""Test that no warning is shown when sync client is provided."""
49+
# Reset the warning flag for testing
50+
EmbeddingsCache._warning_shown = False
51+
52+
# Create sync redis client
53+
sync_client = Redis.from_url("redis://localhost:6379")
54+
55+
# Initialize EmbeddingsCache with sync_redis_client
56+
cache = EmbeddingsCache(name="test_cache", redis_client=sync_client)
57+
58+
with patch("redisvl.utils.log.get_logger") as mock_logger:
59+
# Sync methods should not warn
60+
_ = cache.get_by_key("test_key")
61+
_ = cache.set(text="test", model_name="model", embedding=[0.1, 0.2])
62+
63+
# No warnings should have been logged
64+
mock_logger.return_value.warning.assert_not_called()
65+
66+
sync_client.close()
67+
68+
69+
@pytest.mark.asyncio
70+
async def test_async_methods_no_warning():
71+
"""Test that async methods don't trigger warnings."""
72+
# Reset the warning flag for testing
73+
EmbeddingsCache._warning_shown = False
74+
75+
# Create async redis client
76+
async_client = RedisConnectionFactory.get_async_redis_connection(
77+
"redis://localhost:6379"
78+
)
79+
80+
# Initialize EmbeddingsCache with only async_redis_client
81+
cache = EmbeddingsCache(name="test_cache", async_redis_client=async_client)
82+
83+
with patch("redisvl.utils.log.get_logger") as mock_logger:
84+
# Async methods should not warn
85+
_ = await cache.aget_by_key("test_key")
86+
_ = await cache.aset(text="test", model_name="model", embedding=[0.1, 0.2])
87+
88+
# No warnings should have been logged
89+
mock_logger.return_value.warning.assert_not_called()
90+
91+
await async_client.aclose()

0 commit comments

Comments
 (0)