redis handler implemented Servies Task has redis object

This commit is contained in:
2025-08-20 22:25:24 +03:00
parent 4e6774a15b
commit 9dd8740171
11 changed files with 223 additions and 152 deletions

View File

@@ -88,6 +88,13 @@ class BuildingCluster(BaseModel):
build_parts: List['BuildPart'] = []
class BuildRequirements(BaseModel):
building_count: int
living_space: int
build_parts: int
# Update forward references for models with circular dependencies
BuildPart.update_forward_refs()
BuildingCluster.update_forward_refs()

View File

@@ -4,8 +4,7 @@ from json import loads, dumps
from contextlib import contextmanager
from time import sleep
from redis import Redis, RedisError, ConnectionError as RedisConnectionError
from config import RedisConfig
from .config import RedisConfig
logger = logging.getLogger('RedisHandler')
@@ -43,35 +42,28 @@ class RedisHandler:
return cls._instance
def __init__(self):
# Initialize only once
if self._initialized:
return
# Initialize Redis client with retry logic
self.redis_client = self._create_redis_client()
self.redis_connected = self._check_redis_connection()
self._initialized = True
def _create_redis_client(self):
"""Create a Redis client with connection retry"""
max_retries = 5
retry_delay = 5
max_retries, retry_delay = 5, 5
for attempt in range(max_retries):
try:
client = Redis(**RedisConfig.as_dict())
client.ping() # Test the connection
client.ping()
logger.info("Redis connection established successfully")
return client
except (RedisConnectionError, RedisError) as e:
if attempt < max_retries - 1:
logger.warning(f"Redis connection attempt {attempt + 1} failed: {str(e)}. Retrying in {retry_delay} seconds...")
sleep(retry_delay)
retry_delay *= 2 # Exponential backoff
retry_delay *= 2
else:
logger.error(f"Failed to connect to Redis after {max_retries} attempts: {str(e)}")
# Continue with a new Redis client instance even if ping fails
# This allows the service to start and retry connections later
return Redis(**RedisConfig.as_dict())
def _check_redis_connection(self) -> bool:
@@ -81,11 +73,11 @@ class RedisHandler:
return True
except Exception as e:
return False
def ping(self):
"""Ping Redis server to check connection"""
return self.redis_client.ping()
def sadd(self, key: str, value):
"""Add a value to a Redis set"""
return self.redis_client.sadd(key, value)
@@ -93,11 +85,22 @@ class RedisHandler:
def ismember(self, key: str, value):
"""Check if a value is a member of a Redis set"""
return self.redis_client.sismember(key, value)
def get(self, key: str):
"""Get a value from Redis by key"""
return self.redis_client.get(key)
def get_json(self, key: str) -> dict:
"""Get a value from Redis by key"""
obj = self.redis_client.get(key)
if obj:
return loads(obj)
return None
def set_json(self, key: str, value):
"""Set a key-value pair in Redis"""
return self.redis_client.set(key, dumps(value))
def set(self, key: str, value):
"""Set a key-value pair in Redis"""
return self.redis_client.set(key, value)
@@ -139,7 +142,7 @@ class RedisHandler:
logger.error(f"Failed to re-establish Redis connection: {str(e)}")
return False
return True
@classmethod
def handle_reconnection(cls, consecutive_errors=0, max_consecutive_errors=5):
"""
@@ -151,12 +154,9 @@ class RedisHandler:
tuple: (RedisHandler instance, bool indicating if extended sleep is needed)
"""
try:
# Get a fresh instance (will reconnect internally)
instance = cls()
instance.redis_connected = instance._check_redis_connection()
logger.info("Recreated Redis handler using singleton pattern")
# Determine if extended sleep is needed
need_extended_sleep = consecutive_errors >= max_consecutive_errors
if need_extended_sleep:
logger.warning(f"Hit {max_consecutive_errors} consecutive Redis errors, taking longer pause")
@@ -165,3 +165,8 @@ class RedisHandler:
logger.error(f"Failed to recreate Redis handler: {str(redis_retry_error)}")
return None, consecutive_errors >= max_consecutive_errors
class RedisSaveModels:
COMMENT_BUILDING_CLUSTER = "COMMENT:PARSER:BUILDING:CLUSTER"
COMMENT_BUILDING_INFO = "COMMENT:PARSER:BUILDING:INFO"

View File

@@ -6,8 +6,9 @@ import aio_pika
from aio_pika.abc import AbstractIncomingMessage
from typing import Any, Dict, Awaitable, Callable, Optional, List
from app.services.types.task import _MsgCtx, _MSG_CTX
from app.services.types.queue import Enqueue
from services.types.task import _MsgCtx, _MSG_CTX
from services.types.queue import Enqueue
class ServiceBaseAsync: