11import os
2+ import asyncio
23from redis import asyncio as aioredis
34from dotenv import load_dotenv
45
@@ -15,30 +16,55 @@ class RedisClient:
1516 """Service for managing Redis connections with proper lifecycle management."""
1617
1718 _instance = None
19+ _client = None
20+ _lock = asyncio .Lock ()
1821
1922 @classmethod
2023 async def get_instance (cls ) -> aioredis .Redis :
21- """Get or create a Redis client instance."""
22- if cls ._instance is None :
23- cls ._instance = cls ()
24- await cls ._instance .initialize ()
25- return cls ._instance .client
24+ """Get or create a Redis client instance with proper singleton behavior."""
25+ if cls ._client is None :
26+ async with cls ._lock :
27+ # Double-check pattern to prevent race conditions
28+ if cls ._client is None :
29+ if cls ._instance is None :
30+ cls ._instance = cls ()
31+ await cls ._instance .initialize ()
32+ return cls ._client
2633
27- def __init__ (self ):
28- self .client = None
2934
3035 async def initialize (self ) -> None :
31- """Initialize the Redis client."""
32- self .client = aioredis .from_url (
33- REDIS_URL ,
34- password = REDIS_PASSWORD ,
35- decode_responses = True ,
36- health_check_interval = 30
37- )
38-
39- async def close (self ) -> None :
40- """Close the Redis client connection."""
41- if self .client :
42- await self .client .close ()
43- self .client = None
44- print ("Redis client closed." )
36+ """Initialize the Redis client with connection pool limits."""
37+ if RedisClient ._client is None :
38+ try :
39+ RedisClient ._client = aioredis .from_url (
40+ REDIS_URL ,
41+ password = REDIS_PASSWORD ,
42+ decode_responses = True ,
43+ health_check_interval = 30 ,
44+ max_connections = 20 , # Limit connection pool size
45+ retry_on_timeout = True ,
46+ socket_keepalive = True ,
47+ socket_keepalive_options = {}
48+ )
49+ print (f"Redis client initialized with connection pool (max 20 connections)" )
50+
51+ # Test the connection
52+ await RedisClient ._client .ping ()
53+
54+ except Exception as e :
55+ print (f"Failed to initialize Redis client: { e } " )
56+ RedisClient ._client = None
57+ raise
58+
59+ @classmethod
60+ async def close (cls ) -> None :
61+ """Close the Redis client connection and reset singleton state."""
62+ if cls ._client :
63+ try :
64+ await cls ._client .close ()
65+ print ("Redis client closed." )
66+ except Exception as e :
67+ print (f"Error closing Redis client: { e } " )
68+ finally :
69+ cls ._client = None
70+ cls ._instance = None
0 commit comments