Fix redis ssl issues 2

This commit is contained in:
2026-01-24 19:28:29 +01:00
parent 08f84e951a
commit c56c558618
11 changed files with 174 additions and 122 deletions

View File

@@ -44,6 +44,7 @@ class InventoryScheduler:
# Leader election
self._redis_url = redis_url
self._leader_election = None
self._redis_manager = None
self._redis_client = None
self._scheduler_started = False
@@ -58,20 +59,15 @@ class InventoryScheduler:
async def _start_with_leader_election(self):
"""Start with Redis-based leader election for horizontal scaling"""
import ssl
import redis.asyncio as redis
from shared.leader_election import LeaderElectionService
from shared.redis_utils import RedisConnectionManager
try:
# Create Redis connection with proper SSL handling for self-signed certificates
connection_kwargs = {"decode_responses": False}
# Handle SSL/TLS for rediss:// URLs (self-signed certificates)
if self._redis_url and self._redis_url.startswith("rediss://"):
connection_kwargs["ssl_cert_reqs"] = ssl.CERT_NONE
self._redis_client = redis.from_url(self._redis_url, **connection_kwargs)
await self._redis_client.ping()
# Create Redis connection using shared manager (handles SSL, pooling, health checks)
self._redis_manager = await RedisConnectionManager.create(
self._redis_url, decode_responses=False
)
self._redis_client = self._redis_manager.get_client()
# Create scheduler (but don't start it yet)
self.scheduler = AsyncIOScheduler()
@@ -180,9 +176,9 @@ class InventoryScheduler:
# Stop scheduler
await self._stop_scheduler()
# Close Redis
if self._redis_client:
await self._redis_client.close()
# Close Redis manager (handles client and pool cleanup)
if hasattr(self, '_redis_manager') and self._redis_manager:
await self._redis_manager.close()
logger.info("Inventory scheduler stopped")

View File

@@ -62,16 +62,14 @@ async def test_deduplication_in_container():
async def start(self):
# Connect to Redis for deduplication testing
import ssl
connection_kwargs = {}
if self.config.REDIS_URL and self.config.REDIS_URL.startswith("rediss://"):
connection_kwargs["ssl_cert_reqs"] = ssl.CERT_NONE
self.redis = await aioredis.from_url(self.config.REDIS_URL, **connection_kwargs)
from shared.redis_utils import RedisConnectionManager
self._redis_manager = await RedisConnectionManager.create(self.config.REDIS_URL)
self.redis = self._redis_manager.get_client()
print(f"✅ Connected to Redis for testing")
async def stop(self):
if self.redis:
await self.redis.aclose()
if hasattr(self, '_redis_manager') and self._redis_manager:
await self._redis_manager.close()
# Create test service
service = TestInventoryAlertService()

View File

@@ -100,24 +100,18 @@ class OrchestratorService(StandardFastAPIService):
Without leader election, each pod would run the same scheduled jobs,
causing duplicate forecasts, production schedules, and database contention.
"""
import ssl
from shared.leader_election import LeaderElectionService
import redis.asyncio as redis
from shared.redis_utils import RedisConnectionManager
try:
# Create Redis connection for leader election
redis_url = f"redis://:{settings.REDIS_PASSWORD}@{settings.REDIS_HOST}:{settings.REDIS_PORT}/{settings.REDIS_DB}"
use_tls = settings.REDIS_TLS_ENABLED.lower() == "true"
if use_tls:
if settings.REDIS_TLS_ENABLED.lower() == "true":
redis_url = redis_url.replace("redis://", "rediss://")
# Handle SSL/TLS for self-signed certificates
connection_kwargs = {"decode_responses": False}
if use_tls:
connection_kwargs["ssl_cert_reqs"] = ssl.CERT_NONE
redis_client = redis.from_url(redis_url, **connection_kwargs)
await redis_client.ping()
# Create Redis connection using shared manager (handles SSL, pooling, health checks)
self.redis_manager = await RedisConnectionManager.create(redis_url, decode_responses=False)
redis_client = self.redis_manager.get_client()
# Use shared leader election service
self.leader_election = LeaderElectionService(
@@ -180,6 +174,11 @@ class OrchestratorService(StandardFastAPIService):
await self.scheduler_service.stop()
self.logger.info("Orchestrator scheduler service stopped")
# Close Redis manager (handles client and pool cleanup)
if hasattr(self, 'redis_manager') and self.redis_manager:
await self.redis_manager.close()
self.logger.info("Redis connection closed")
def get_service_features(self):
"""Return orchestrator-specific features"""

View File

@@ -52,6 +52,7 @@ class POSScheduler:
# Leader election
self._redis_url = redis_url
self._leader_election = None
self._redis_manager = None
self._redis_client = None
self._scheduler_started = False
@@ -66,18 +67,15 @@ class POSScheduler:
async def _start_with_leader_election(self):
"""Start with Redis-based leader election for horizontal scaling"""
import ssl
import redis.asyncio as redis
from shared.leader_election import LeaderElectionService
from shared.redis_utils import RedisConnectionManager
try:
# Create Redis connection with proper SSL handling for self-signed certificates
connection_kwargs = {"decode_responses": False}
if self._redis_url and self._redis_url.startswith("rediss://"):
connection_kwargs["ssl_cert_reqs"] = ssl.CERT_NONE
self._redis_client = redis.from_url(self._redis_url, **connection_kwargs)
await self._redis_client.ping()
# Create Redis connection using shared manager (handles SSL, pooling, health checks)
self._redis_manager = await RedisConnectionManager.create(
self._redis_url, decode_responses=False
)
self._redis_client = self._redis_manager.get_client()
# Create scheduler (but don't start it yet)
self.scheduler = AsyncIOScheduler()
@@ -201,9 +199,9 @@ class POSScheduler:
# Stop scheduler
await self._stop_scheduler()
# Close Redis
if self._redis_client:
await self._redis_client.close()
# Close Redis manager (handles client and pool cleanup)
if self._redis_manager:
await self._redis_manager.close()
logger.info("POS scheduler stopped")

View File

@@ -39,6 +39,7 @@ class DeliveryTrackingService:
self.database_manager = database_manager
self.scheduler = AsyncIOScheduler()
self._leader_election = None
self._redis_manager = None
self._redis_client = None
self._scheduler_started = False
self.instance_id = str(uuid4())[:8] # Short instance ID for logging
@@ -56,9 +57,8 @@ class DeliveryTrackingService:
async def _setup_leader_election(self):
"""Setup Redis-based leader election for horizontal scaling"""
import ssl
from shared.leader_election import LeaderElectionService
import redis.asyncio as redis
from shared.redis_utils import RedisConnectionManager
# Build Redis URL from config
redis_url = getattr(self.config, 'REDIS_URL', None)
@@ -69,13 +69,9 @@ class DeliveryTrackingService:
redis_db = getattr(self.config, 'REDIS_DB', 0)
redis_url = f"redis://:{redis_password}@{redis_host}:{redis_port}/{redis_db}"
# Handle SSL/TLS for self-signed certificates
connection_kwargs = {"decode_responses": False}
if redis_url and redis_url.startswith("rediss://"):
connection_kwargs["ssl_cert_reqs"] = ssl.CERT_NONE
self._redis_client = redis.from_url(redis_url, **connection_kwargs)
await self._redis_client.ping()
# Create Redis connection using shared manager (handles SSL, pooling, health checks)
self._redis_manager = await RedisConnectionManager.create(redis_url, decode_responses=False)
self._redis_client = self._redis_manager.get_client()
# Create leader election service
self._leader_election = LeaderElectionService(
@@ -151,9 +147,9 @@ class DeliveryTrackingService:
# Stop scheduler
await self._stop_scheduler()
# Close Redis
if self._redis_client:
await self._redis_client.close()
# Close Redis manager (handles client and pool cleanup)
if self._redis_manager:
await self._redis_manager.close()
@property
def is_leader(self) -> bool:

View File

@@ -40,6 +40,7 @@ class ProductionScheduler:
# Leader election
self._leader_election = None
self._redis_manager = None
self._redis_client = None
self._scheduler_started = False
@@ -65,17 +66,12 @@ class ProductionScheduler:
async def _setup_leader_election(self):
"""Setup Redis-based leader election"""
import ssl
from shared.leader_election import LeaderElectionService
import redis.asyncio as redis
from shared.redis_utils import RedisConnectionManager
# Handle SSL/TLS for self-signed certificates
connection_kwargs = {"decode_responses": False}
if self.redis_url and self.redis_url.startswith("rediss://"):
connection_kwargs["ssl_cert_reqs"] = ssl.CERT_NONE
self._redis_client = redis.from_url(self.redis_url, **connection_kwargs)
await self._redis_client.ping()
# Create Redis connection using shared manager (handles SSL, pooling, health checks)
self._redis_manager = await RedisConnectionManager.create(self.redis_url, decode_responses=False)
self._redis_client = self._redis_manager.get_client()
self._leader_election = LeaderElectionService(
self._redis_client,
@@ -137,8 +133,9 @@ class ProductionScheduler:
await self._stop_scheduler()
if self._redis_client:
await self._redis_client.close()
# Close Redis manager (handles client and pool cleanup)
if self._redis_manager:
await self._redis_manager.close()
@property
def is_leader(self) -> bool:

View File

@@ -365,21 +365,14 @@ class AlertEventConsumer:
# Redis-based rate limiting implementation
try:
import ssl
import redis.asyncio as redis
from datetime import datetime, timedelta
from app.core.config import Settings
from shared.redis_utils import RedisConnectionManager
# Connect to Redis using proper configuration with TLS and auth
# Connect to Redis using shared manager (handles SSL, pooling, health checks)
settings = Settings()
redis_url = settings.REDIS_URL
# Handle SSL/TLS for self-signed certificates
connection_kwargs = {"decode_responses": True}
if redis_url and redis_url.startswith("rediss://"):
connection_kwargs["ssl_cert_reqs"] = ssl.CERT_NONE
redis_client = await redis.from_url(redis_url, **connection_kwargs)
redis_manager = await RedisConnectionManager.create(settings.REDIS_URL, decode_responses=True)
redis_client = redis_manager.get_client()
# Rate limit keys
hour_key = f"alert_rate_limit:{tenant_id}:{alert_type}:hour:{datetime.utcnow().strftime('%Y%m%d%H')}"
@@ -404,7 +397,7 @@ class AlertEventConsumer:
count=hour_count,
limit=max_per_hour
)
await redis_client.close()
await redis_manager.close()
return False
if day_count >= max_per_day:
@@ -415,7 +408,7 @@ class AlertEventConsumer:
count=day_count,
limit=max_per_day
)
await redis_client.close()
await redis_manager.close()
return False
# Increment counters
@@ -426,7 +419,7 @@ class AlertEventConsumer:
pipe.expire(day_key, 86400) # 24 hour TTL
await pipe.execute()
await redis_client.close()
await redis_manager.close()
logger.debug(
"Rate limit check passed",

View File

@@ -49,17 +49,13 @@ class UsageForecastResponse(BaseModel):
async def get_redis_client() -> redis.Redis:
"""Get Redis client for usage tracking"""
import ssl
from shared.redis_utils import RedisConnectionManager
# Handle SSL/TLS for self-signed certificates
connection_kwargs = {
"encoding": "utf-8",
"decode_responses": True
}
if settings.REDIS_URL and settings.REDIS_URL.startswith("rediss://"):
connection_kwargs["ssl_cert_reqs"] = ssl.CERT_NONE
return redis.from_url(settings.REDIS_URL, **connection_kwargs)
# Create Redis connection using shared manager (handles SSL, pooling, health checks)
manager = await RedisConnectionManager.create(
settings.REDIS_URL, decode_responses=True
)
return manager.get_client()
async def get_usage_history(