Skip to content

Commit a56a6b7

Browse files
authored
Fix docker issues, TTL cleanup (#58)
* Standardize on using _apply_ttl_to_keys * Fix redis container docker issues
1 parent b4fad1c commit a56a6b7

File tree

7 files changed

+35
-34
lines changed

7 files changed

+35
-34
lines changed

langgraph/checkpoint/redis/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from __future__ import annotations
22

33
import json
4-
from contextlib import contextmanager
54
import logging
5+
from contextlib import contextmanager
66
from typing import Any, Dict, Iterator, List, Optional, Tuple, Union, cast
77

88
from langchain_core.runnables import RunnableConfig

langgraph/checkpoint/redis/aio.py

Lines changed: 10 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -595,16 +595,10 @@ async def aput(
595595

596596
# Apply TTL if configured
597597
if self.ttl_config and "default_ttl" in self.ttl_config:
598-
all_keys = (
599-
[checkpoint_key] + [key for key, _ in blobs]
600-
if blobs
601-
else [checkpoint_key]
598+
await self._apply_ttl_to_keys(
599+
checkpoint_key,
600+
[key for key, _ in blobs] if blobs else None,
602601
)
603-
ttl_minutes = self.ttl_config.get("default_ttl")
604-
ttl_seconds = int(ttl_minutes * 60)
605-
606-
for key in all_keys:
607-
await self._redis.expire(key, ttl_seconds)
608602
else:
609603
# For non-cluster mode, use pipeline with transaction for atomicity
610604
pipeline = self._redis.pipeline(transaction=True)
@@ -622,19 +616,10 @@ async def aput(
622616

623617
# Apply TTL to checkpoint and blob keys if configured
624618
if self.ttl_config and "default_ttl" in self.ttl_config:
625-
all_keys = (
626-
[checkpoint_key] + [key for key, _ in blobs]
627-
if blobs
628-
else [checkpoint_key]
619+
await self._apply_ttl_to_keys(
620+
checkpoint_key,
621+
[key for key, _ in blobs] if blobs else None,
629622
)
630-
ttl_minutes = self.ttl_config.get("default_ttl")
631-
ttl_seconds = int(ttl_minutes * 60)
632-
633-
# Use a new pipeline for TTL operations
634-
ttl_pipeline = self._redis.pipeline()
635-
for key in all_keys:
636-
ttl_pipeline.expire(key, ttl_seconds)
637-
await ttl_pipeline.execute()
638623

639624
return next_config
640625

@@ -780,11 +765,10 @@ async def aput_writes(
780765
and self.ttl_config
781766
and "default_ttl" in self.ttl_config
782767
):
783-
ttl_minutes = self.ttl_config.get("default_ttl")
784-
ttl_seconds = int(ttl_minutes * 60)
785-
786-
for key in created_keys:
787-
await self._redis.expire(key, ttl_seconds)
768+
await self._apply_ttl_to_keys(
769+
created_keys[0],
770+
created_keys[1:] if len(created_keys) > 1 else None,
771+
)
788772
else:
789773
# For non-cluster mode, use transaction pipeline for atomicity
790774
pipeline = self._redis.pipeline(transaction=True)

langgraph/checkpoint/redis/types.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
from redis import Redis
44
from redis.asyncio import Redis as AsyncRedis
5-
from redis.cluster import RedisCluster
65
from redis.asyncio.cluster import RedisCluster as AsyncRedisCluster
6+
from redis.cluster import RedisCluster
77
from redisvl.index import AsyncSearchIndex, SearchIndex
88

99
RedisClientType = TypeVar(

tests/conftest.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import asyncio
22
import os
3+
import socket
4+
import time
35

46
import pytest
57
from redis.asyncio import Redis
@@ -58,6 +60,20 @@ def redis_url(redis_container):
5860
on container port 6379 (mapped to an ephemeral port on the host).
5961
"""
6062
host, port = redis_container.get_service_host_and_port("redis", 6379)
63+
64+
# Wait up to 15 seconds for the container to accept TCP connections.
65+
deadline = time.time() + 15
66+
while True:
67+
try:
68+
with socket.create_connection((host, int(port)), timeout=1):
69+
break # Redis is accepting connections
70+
except OSError:
71+
if time.time() > deadline:
72+
pytest.skip(
73+
"Redis container failed to become ready for this worker – skipping tests."
74+
)
75+
time.sleep(0.5)
76+
6177
return f"redis://{host}:{port}"
6278

6379

tests/docker-compose.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ services:
33
redis:
44
image: "${REDIS_IMAGE}"
55
ports:
6-
- "6379"
6+
- target: 6379
7+
published: 0
8+
protocol: tcp
9+
mode: host
710
environment:
811
- "REDIS_ARGS=--save '' --appendonly no"
912
deploy:
1013
replicas: 1
1114
restart_policy:
1215
condition: on-failure
13-
labels:
14-
- "com.docker.compose.publishers=redis,6379,6379"

tests/test_async_cluster_mode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
RedisCluster as AsyncRedisCluster, # Import actual for isinstance checks if needed by store
1111
)
1212

13-
from langgraph.store.redis import AsyncRedisStore
1413
from langgraph.checkpoint.redis.aio import AsyncRedisSaver
14+
from langgraph.store.redis import AsyncRedisStore
1515

1616

1717
# Override session-scoped redis_container fixture to prevent Docker operations and provide dummy host/port

tests/test_cluster_mode.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@
77
from unittest.mock import MagicMock
88

99
import pytest
10+
from langgraph.checkpoint.base import Checkpoint, CheckpointMetadata
1011
from langgraph.store.base import GetOp, ListNamespacesOp, PutOp, SearchOp
1112
from redis import Redis
1213
from redis.cluster import RedisCluster as SyncRedisCluster
1314
from ulid import ULID
1415

16+
from langgraph.checkpoint.redis import RedisSaver
1517
from langgraph.store.redis import RedisStore
1618
from langgraph.store.redis.base import (
1719
REDIS_KEY_SEPARATOR,
1820
STORE_PREFIX,
1921
STORE_VECTOR_PREFIX,
2022
)
21-
from langgraph.checkpoint.redis import RedisSaver
22-
from langgraph.checkpoint.base import Checkpoint, CheckpointMetadata
2323

2424

2525
# Override session-scoped redis_container fixture to prevent Docker operations and provide dummy host/port

0 commit comments

Comments
 (0)