Skip to content

Commit 2e1c882

Browse files
committed
feat(client-info)!: add full library version info to Redis client tracking
- Add client_setinfo calls in RedisSaver.configure_client() to register library version with Redis - Update all set_client_info/aset_client_info methods to use __full_lib_name__ instead of __redisvl_version__ - Ensure graceful error handling with fallback to echo() and silent failure - Remove redundant test_jsonplus_redis_serializer.py from root directory - Update all client info tests to expect full library name format - Add client_setinfo/echo mock methods to BaseMockRedis for cluster mode tests BREAKING CHANGE: Client info now sends complete version string format: redis-py(redisvl_v{version};langgraph-checkpoint-redis_v{version}) This provides better visibility in Redis CLIENT LIST for monitoring and debugging, showing redis-py client, RedisVL version, and checkpoint-redis library version.
1 parent 877fc60 commit 2e1c882

File tree

11 files changed

+1694
-1657
lines changed

11 files changed

+1694
-1657
lines changed

langgraph/checkpoint/redis/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,26 @@ def configure_client(
9494
connection_args: Optional[Dict[str, Any]] = None,
9595
) -> None:
9696
"""Configure the Redis client."""
97+
from redis.exceptions import ResponseError
98+
99+
from langgraph.checkpoint.redis.version import __full_lib_name__
100+
97101
self._owns_its_client = redis_client is None
98102
self._redis = redis_client or RedisConnectionFactory.get_redis_connection(
99103
redis_url, **connection_args
100104
)
101105

106+
# Set client info for Redis monitoring
107+
try:
108+
self._redis.client_setinfo("LIB-NAME", __full_lib_name__)
109+
except (ResponseError, AttributeError):
110+
# Fall back to a simple echo if client_setinfo is not available
111+
try:
112+
self._redis.echo(__full_lib_name__)
113+
except Exception:
114+
# Silently fail if even echo doesn't work
115+
pass
116+
102117
def create_indexes(self) -> None:
103118
self.checkpoints_index = SearchIndex.from_dict(
104119
self.SCHEMAS[0], redis_client=self._redis

langgraph/checkpoint/redis/base.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -175,19 +175,16 @@ async def aset_client_info(self) -> None:
175175
"""Set client info for Redis monitoring asynchronously."""
176176
from redis.exceptions import ResponseError
177177

178-
from langgraph.checkpoint.redis.version import __redisvl_version__
179-
180-
# Create the client info string with only the redisvl version
181-
client_info = f"redis-py(redisvl_v{__redisvl_version__})"
178+
from langgraph.checkpoint.redis.version import __full_lib_name__
182179

183180
try:
184181
# Try to use client_setinfo command if available
185-
await self._redis.client_setinfo("LIB-NAME", client_info)
182+
await self._redis.client_setinfo("LIB-NAME", __full_lib_name__)
186183
except (ResponseError, AttributeError):
187184
# Fall back to a simple echo if client_setinfo is not available
188185
try:
189186
# Call with await to ensure it's an async call
190-
echo_result = self._redis.echo(client_info)
187+
echo_result = self._redis.echo(__full_lib_name__)
191188
if hasattr(echo_result, "__await__"):
192189
await echo_result
193190
except Exception:

langgraph/store/redis/base.py

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -325,38 +325,32 @@ def __init__(
325325
def set_client_info(self) -> None:
326326
"""Set client info for Redis monitoring."""
327327

328-
from langgraph.checkpoint.redis.version import __redisvl_version__
329-
330-
# Create the client info string with only the redisvl version
331-
client_info = f"redis-py(redisvl_v{__redisvl_version__})"
328+
from langgraph.checkpoint.redis.version import __full_lib_name__
332329

333330
try:
334331
# Try to use client_setinfo command if available
335-
self._redis.client_setinfo("LIB-NAME", client_info)
332+
self._redis.client_setinfo("LIB-NAME", __full_lib_name__)
336333
except (ResponseError, AttributeError):
337334
# Fall back to a simple echo if client_setinfo is not available
338335
try:
339-
self._redis.echo(client_info)
336+
self._redis.echo(__full_lib_name__)
340337
except Exception:
341338
# Silently fail if even echo doesn't work
342339
pass
343340

344341
async def aset_client_info(self) -> None:
345342
"""Set client info for Redis monitoring asynchronously."""
346343

347-
from langgraph.checkpoint.redis.version import __redisvl_version__
348-
349-
# Create the client info string with only the redisvl version
350-
client_info = f"redis-py(redisvl_v{__redisvl_version__})"
344+
from langgraph.checkpoint.redis.version import __full_lib_name__
351345

352346
try:
353347
# Try to use client_setinfo command if available
354-
await self._redis.client_setinfo("LIB-NAME", client_info)
348+
await self._redis.client_setinfo("LIB-NAME", __full_lib_name__)
355349
except (ResponseError, AttributeError):
356350
# Fall back to a simple echo if client_setinfo is not available
357351
try:
358352
# Call with await to ensure it's an async call
359-
echo_result = self._redis.echo(client_info)
353+
echo_result = self._redis.echo(__full_lib_name__)
360354
if hasattr(echo_result, "__await__"):
361355
await echo_result
362356
except Exception:

poetry.lock

Lines changed: 1642 additions & 1426 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test_jsonplus_redis_serializer.py

Lines changed: 0 additions & 167 deletions
This file was deleted.

tests/test_async.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,10 +283,7 @@ async def test_from_conn_string_cleanup(redis_url: str) -> None:
283283
@pytest.mark.asyncio
284284
async def test_async_client_info_setting(redis_url: str, monkeypatch) -> None:
285285
"""Test that async client_setinfo is called with correct library information."""
286-
from langgraph.checkpoint.redis.version import __redisvl_version__
287-
288-
# Expected client info format
289-
expected_client_info = f"redis-py(redisvl_v{__redisvl_version__})"
286+
from langgraph.checkpoint.redis.version import __full_lib_name__
290287

291288
# Track if client_setinfo was called with the right parameters
292289
client_info_called = False
@@ -297,9 +294,8 @@ async def test_async_client_info_setting(redis_url: str, monkeypatch) -> None:
297294
# Create a mock function for client_setinfo
298295
async def mock_client_setinfo(self, key, value):
299296
nonlocal client_info_called
300-
# Note: RedisVL might call this with its own lib name first
301-
# We only track calls with our full lib name
302-
if key == "LIB-NAME" and value == expected_client_info:
297+
# Track calls with our full lib name
298+
if key == "LIB-NAME" and value == __full_lib_name__:
303299
client_info_called = True
304300
# Call original method to ensure normal function
305301
return await original_client_setinfo(self, key, value)

tests/test_async_store.py

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -544,10 +544,7 @@ async def test_async_redis_store_client_info(redis_url: str, monkeypatch) -> Non
544544
"""Test that AsyncRedisStore sets client info correctly."""
545545
from redis.asyncio import Redis
546546

547-
from langgraph.checkpoint.redis.version import __redisvl_version__
548-
549-
# Expected client info format
550-
expected_client_info = f"redis-py(redisvl_v{__redisvl_version__})"
547+
from langgraph.checkpoint.redis.version import __full_lib_name__
551548

552549
# Track if client_setinfo was called with the right parameters
553550
client_info_called = False
@@ -558,9 +555,8 @@ async def test_async_redis_store_client_info(redis_url: str, monkeypatch) -> Non
558555
# Create a mock function for client_setinfo
559556
async def mock_client_setinfo(self, key, value):
560557
nonlocal client_info_called
561-
# Note: RedisVL might call this with its own lib name first
562-
# We only track calls with our full lib name
563-
if key == "LIB-NAME" and value == expected_client_info:
558+
# Track calls with our full lib name
559+
if key == "LIB-NAME" and value == __full_lib_name__:
564560
client_info_called = True
565561
# Call original method to ensure normal function
566562
return await original_client_setinfo(self, key, value)
@@ -584,10 +580,7 @@ async def test_async_redis_store_client_info_fallback(
584580
from redis.asyncio import Redis
585581
from redis.exceptions import ResponseError
586582

587-
from langgraph.checkpoint.redis.version import __redisvl_version__
588-
589-
# Expected client info format
590-
expected_client_info = f"redis-py(redisvl_v{__redisvl_version__})"
583+
from langgraph.checkpoint.redis.version import __full_lib_name__
591584

592585
# Remove client_setinfo to simulate older Redis version
593586
async def mock_client_setinfo(self, key, value):
@@ -601,7 +594,7 @@ async def mock_client_setinfo(self, key, value):
601594
async def mock_echo(self, message):
602595
nonlocal echo_called
603596
echo_called = True
604-
assert message == expected_client_info
597+
assert message == __full_lib_name__
605598
return await original_echo(self, message)
606599

607600
# Apply the mocks

tests/test_base_client_info_and_ttl.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,10 @@ async def test_aset_client_info_success():
9090
# Mock async client_setinfo
9191
saver._redis.client_setinfo = AsyncMock()
9292

93-
with patch("langgraph.checkpoint.redis.version.__redisvl_version__", "1.2.3"):
93+
with patch("langgraph.checkpoint.redis.version.__full_lib_name__", "test-lib-v1.0"):
9494
await saver.aset_client_info()
9595

96-
saver._redis.client_setinfo.assert_called_once_with(
97-
"LIB-NAME", "redis-py(redisvl_v1.2.3)"
98-
)
96+
saver._redis.client_setinfo.assert_called_once_with("LIB-NAME", "test-lib-v1.0")
9997

10098

10199
@pytest.mark.asyncio
@@ -112,7 +110,7 @@ async def mock_echo(msg):
112110

113111
saver._redis.echo = mock_echo
114112

115-
with patch("langgraph.checkpoint.redis.version.__redisvl_version__", "1.2.3"):
113+
with patch("langgraph.checkpoint.redis.version.__full_lib_name__", "test-lib-v1.0"):
116114
await saver.aset_client_info()
117115

118116
saver._redis.client_setinfo.assert_called_once()

tests/test_cluster_mode.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ def cluster(self, subcmd: str, *args, **kwargs):
9292
raise ResponseError("ERR This instance has cluster support disabled")
9393
return {}
9494

95+
def client_setinfo(self, key, value):
96+
"""Mock client_setinfo for testing."""
97+
return "OK"
98+
99+
def echo(self, message):
100+
"""Mock echo for testing."""
101+
return message
102+
95103

96104
class MockRedis(BaseMockRedis, Redis):
97105
pass

0 commit comments

Comments
 (0)