Skip to content

Commit d689975

Browse files
committed
fix(tests): implement proper cleanup for async Redis clients
- Add global async_redis_client variable for reuse - Implement close_async_redis_client function for proper cleanup - Update test cases to include asyncTearDown method for cleanup - Remove python3.8 from test environment due to end of support
1 parent 27abbbc commit d689975

File tree

4 files changed

+61
-29
lines changed

4 files changed

+61
-29
lines changed

tests/_catches.py

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from os import getenv
2-
from typing import Callable, Dict, List
2+
from typing import Callable, Dict, List, Optional
33
from warnings import warn
44

55
from redis import Redis
@@ -35,56 +35,76 @@
3535
load_dotenv()
3636

3737

38+
redis_client: Optional[Redis] = None
39+
async_redis_client: Optional[AsyncRedis] = None
40+
41+
3842
def redis_factory(**kwargs):
39-
return Redis.from_url(REDIS_URL)
43+
global redis_client
44+
if redis_client is None:
45+
redis_client = Redis.from_url(REDIS_URL)
46+
return redis_client
4047

4148

4249
def async_redis_factory(**kwargs):
43-
return AsyncRedis.from_url(REDIS_URL)
50+
global async_redis_client
51+
if async_redis_client is None:
52+
async_redis_client = AsyncRedis.from_url(REDIS_URL)
53+
return async_redis_client
54+
55+
56+
async def close_async_redis_client():
57+
"""关闭全局异步Redis客户端连接"""
58+
global async_redis_client
59+
if async_redis_client is not None:
60+
await async_redis_client.close()
61+
async_redis_client = None
4462

4563

4664
MAXSIZE = 8
4765

4866
REDIS_URL = getenv("REDIS_URL", "redis://")
67+
REDIS_FACTORY = lambda: Redis.from_url(REDIS_URL) # noqa: E731
68+
ASYNC_REDIS_FACTORY = lambda: AsyncRedis.from_url(REDIS_URL) # noqa: E731
4969
REDIS_CLUSTER_NODES = getenv("REDIS_CLUSTER_NODES")
5070

5171

5272
CACHES = {
53-
"tlru": RedisFuncCache(__name__, LruTPolicy, client=redis_factory, maxsize=MAXSIZE),
54-
"lru": RedisFuncCache(__name__, LruPolicy, client=redis_factory, maxsize=MAXSIZE),
55-
"mru": RedisFuncCache(__name__, MruPolicy, client=redis_factory, maxsize=MAXSIZE),
56-
"rr": RedisFuncCache(__name__, RrPolicy, client=redis_factory, maxsize=MAXSIZE),
57-
"fifo": RedisFuncCache(__name__, FifoPolicy, client=redis_factory, maxsize=MAXSIZE),
58-
"lfu": RedisFuncCache(__name__, LfuPolicy, client=redis_factory, maxsize=MAXSIZE),
73+
"tlru": RedisFuncCache(__name__, LruTPolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
74+
"lru": RedisFuncCache(__name__, LruPolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
75+
"mru": RedisFuncCache(__name__, MruPolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
76+
"rr": RedisFuncCache(__name__, RrPolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
77+
"fifo": RedisFuncCache(__name__, FifoPolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
78+
"lfu": RedisFuncCache(__name__, LfuPolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
5979
}
6080

6181
MULTI_CACHES = {
62-
"tlru": RedisFuncCache(__name__, LruTMultiplePolicy, client=redis_factory, maxsize=MAXSIZE),
63-
"lru": RedisFuncCache(__name__, LruMultiplePolicy, client=redis_factory, maxsize=MAXSIZE),
64-
"mru": RedisFuncCache(__name__, MruMultiplePolicy, client=redis_factory, maxsize=MAXSIZE),
65-
"rr": RedisFuncCache(__name__, RrMultiplePolicy, client=redis_factory, maxsize=MAXSIZE),
66-
"fifo": RedisFuncCache(__name__, FifoMultiplePolicy, client=redis_factory, maxsize=MAXSIZE),
67-
"lfu": RedisFuncCache(__name__, LfuMultiplePolicy, client=redis_factory, maxsize=MAXSIZE),
82+
"tlru": RedisFuncCache(__name__, LruTMultiplePolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
83+
"lru": RedisFuncCache(__name__, LruMultiplePolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
84+
"mru": RedisFuncCache(__name__, MruMultiplePolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
85+
"rr": RedisFuncCache(__name__, RrMultiplePolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
86+
"fifo": RedisFuncCache(__name__, FifoMultiplePolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
87+
"lfu": RedisFuncCache(__name__, LfuMultiplePolicy, client=REDIS_FACTORY, maxsize=MAXSIZE),
6888
}
6989

7090

7191
ASYNC_CACHES = {
72-
"tlru": RedisFuncCache(__name__, LruTPolicy, client=async_redis_factory, maxsize=MAXSIZE),
73-
"lru": RedisFuncCache(__name__, LruPolicy, client=async_redis_factory, maxsize=MAXSIZE),
74-
"mru": RedisFuncCache(__name__, MruPolicy, client=async_redis_factory, maxsize=MAXSIZE),
75-
"rr": RedisFuncCache(__name__, RrPolicy, client=async_redis_factory, maxsize=MAXSIZE),
76-
"fifo": RedisFuncCache(__name__, FifoPolicy, client=async_redis_factory, maxsize=MAXSIZE),
77-
"lfu": RedisFuncCache(__name__, LfuPolicy, client=async_redis_factory, maxsize=MAXSIZE),
92+
"tlru": RedisFuncCache(__name__, LruTPolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
93+
"lru": RedisFuncCache(__name__, LruPolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
94+
"mru": RedisFuncCache(__name__, MruPolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
95+
"rr": RedisFuncCache(__name__, RrPolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
96+
"fifo": RedisFuncCache(__name__, FifoPolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
97+
"lfu": RedisFuncCache(__name__, LfuPolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
7898
}
7999

80100

81101
ASYNC_MULTI_CACHES = {
82-
"tlru": RedisFuncCache(__name__, LruTMultiplePolicy, client=async_redis_factory, maxsize=MAXSIZE),
83-
"lru": RedisFuncCache(__name__, LruMultiplePolicy, client=async_redis_factory, maxsize=MAXSIZE),
84-
"mru": RedisFuncCache(__name__, MruMultiplePolicy, client=async_redis_factory, maxsize=MAXSIZE),
85-
"rr": RedisFuncCache(__name__, RrMultiplePolicy, client=async_redis_factory, maxsize=MAXSIZE),
86-
"fifo": RedisFuncCache(__name__, FifoMultiplePolicy, client=async_redis_factory, maxsize=MAXSIZE),
87-
"lfu": RedisFuncCache(__name__, LfuMultiplePolicy, client=async_redis_factory, maxsize=MAXSIZE),
102+
"tlru": RedisFuncCache(__name__, LruTMultiplePolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
103+
"lru": RedisFuncCache(__name__, LruMultiplePolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
104+
"mru": RedisFuncCache(__name__, MruMultiplePolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
105+
"rr": RedisFuncCache(__name__, RrMultiplePolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
106+
"fifo": RedisFuncCache(__name__, FifoMultiplePolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
107+
"lfu": RedisFuncCache(__name__, LfuMultiplePolicy, client=ASYNC_REDIS_FACTORY, maxsize=MAXSIZE),
88108
}
89109

90110
CLUSTER_NODES: List[ClusterNode] = []

tests/run.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export PIP_ROOT_USER_ACTION=ignore
66
export PIP_NO_WARN_SCRIPT_LOCATION=1
77

88

9-
PYTHON_LIST=(python3.8 python3.9 python3.10 python3.11 python3.12 python3.13)
9+
PYTHON_LIST=(python3.9 python3.10 python3.11 python3.12 python3.13)
1010
for PYTHON in ${PYTHON_LIST[@]}
1111
do
1212
echo

tests/test_async.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from unittest import IsolatedAsyncioTestCase
44
from unittest.mock import AsyncMock, patch
55

6-
from ._catches import ASYNC_CACHES, ASYNC_MULTI_CACHES, CACHES
6+
from ._catches import ASYNC_CACHES, ASYNC_MULTI_CACHES, CACHES, close_async_redis_client
77

88

99
def _echo(x):
@@ -15,6 +15,10 @@ async def asyncSetUp(self):
1515
coros = (cache.policy.apurge() for cache in ASYNC_CACHES.values())
1616
await asyncio.gather(*coros)
1717

18+
async def asyncTearDown(self):
19+
# 清理异步Redis客户端连接
20+
await close_async_redis_client()
21+
1822
async def test_simple(self):
1923
for cache in ASYNC_CACHES.values():
2024

@@ -36,6 +40,10 @@ async def asyncSetUp(self):
3640
coros = (cache.policy.apurge() for cache in ASYNC_MULTI_CACHES.values())
3741
await asyncio.gather(*coros)
3842

43+
async def asyncTearDown(self):
44+
# 清理异步Redis客户端连接
45+
await close_async_redis_client()
46+
3947
async def test_simple(self):
4048
for cache in ASYNC_MULTI_CACHES.values():
4149

tests/test_async_context.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ async def asyncSetUp(self):
1111
coros = (cache.policy.apurge() for cache in ASYNC_CACHES.values())
1212
await asyncio.gather(*coros)
1313

14+
async def asyncTearDown(self):
15+
# 正确关闭所有异步Redis客户端连接,防止"Event loop is closed"错误
16+
await asyncio.gather(*(cache.client.close() for cache in ASYNC_CACHES.values()))
17+
1418
async def test_async_ttl_contextual(self):
1519
for cache in ASYNC_CACHES.values():
1620

0 commit comments

Comments
 (0)