import os import json import time from threading import Lock try: import redis except ImportError: redis = None class MemoryCache: def __init__(self): self._cache = {} self._lock = Lock() def get(self, key): with self._lock: if key not in self._cache: return None val, expiry = self._cache[key] if expiry is not None and time.time() > expiry: del self._cache[key] return None return val def set(self, key, value, ttl=None): with self._lock: expiry = time.time() + ttl if ttl is not None else None self._cache[key] = (value, expiry) def delete(self, key): with self._lock: if key in self._cache: del self._cache[key] class CacheManager: def __init__(self): self.redis_url = os.getenv("REDIS_URL", "redis://localhost:6379/0") self.redis_client = None self.use_redis = False if redis is not None: try: self.redis_client = redis.Redis.from_url(self.redis_url, socket_timeout=1.0) # Test connection self.redis_client.ping() self.use_redis = True print("Connected to Redis successfully.") except Exception as e: print(f"Redis connection failed ({e}). Falling back to in-memory cache.") else: print("Redis library not installed. Falling back to in-memory cache.") self.memory_cache = MemoryCache() def get(self, key: str): if self.use_redis: try: val = self.redis_client.get(key) if val: return json.loads(val.decode('utf-8')) except Exception as e: # Fallback to memory on Redis error during operation print(f"Redis get failed ({e}). Using memory cache fallback.") return self.memory_cache.get(key) def set(self, key: str, value, ttl: int = None): if self.use_redis: try: self.redis_client.set(key, json.dumps(value), ex=ttl) return except Exception as e: print(f"Redis set failed ({e}). Using memory cache fallback.") self.memory_cache.set(key, value, ttl) def delete(self, key: str): if self.use_redis: try: self.redis_client.delete(key) return except Exception as e: print(f"Redis delete failed ({e}). Using memory cache fallback.") self.memory_cache.delete(key) # Global cache instance cache = CacheManager()