Spaces:
Runtime error
Runtime error
| # utils/redis_cache.py | |
| import logging | |
| import json | |
| from typing import Any | |
| import config | |
| logger = logging.getLogger(__name__) | |
| _redis = None | |
| _redis_available = None # None=لم يجرَّب، True=يعمل، False=غير متاح | |
| def get_redis(): | |
| global _redis, _redis_available | |
| if _redis_available is False: | |
| return None | |
| if _redis is not None: | |
| return _redis | |
| try: | |
| import redis | |
| r = redis.Redis( | |
| host=config.REDIS_HOST, | |
| port=config.REDIS_PORT, | |
| password=config.REDIS_PASSWORD or None, | |
| db=config.REDIS_DB, | |
| decode_responses=True, | |
| socket_connect_timeout=3, | |
| socket_timeout=3, | |
| ) | |
| r.ping() | |
| _redis = r | |
| _redis_available = True | |
| logger.info("✅ Redis متصل — الكاش نشط") | |
| return _redis | |
| except Exception as e: | |
| _redis_available = False | |
| logger.warning(f"⚠️ Redis غير متاح: {e} — سيعمل البوت بكاش ذاكرة فقط") | |
| return None | |
| # ── كاش الذاكرة الاحتياطي (fallback) ────────────────────── | |
| _mem_cache: dict[str, tuple[Any, float]] = {} | |
| def cache_get(key: str) -> Any | None: | |
| import time | |
| r = get_redis() | |
| if r: | |
| try: | |
| val = r.get(key) | |
| if val: | |
| return json.loads(val) | |
| return None | |
| except Exception: | |
| pass | |
| # fallback للذاكرة | |
| entry = _mem_cache.get(key) | |
| if entry: | |
| value, expires_at = entry | |
| if time.time() < expires_at: | |
| return value | |
| del _mem_cache[key] | |
| return None | |
| def cache_set(key: str, value: Any, ttl: int = None) -> bool: | |
| import time | |
| if ttl is None: | |
| ttl = config.CACHE_TTL # 20 ساعة افتراضياً | |
| r = get_redis() | |
| if r: | |
| try: | |
| r.setex(key, ttl, json.dumps(value, ensure_ascii=False)) | |
| return True | |
| except Exception: | |
| pass | |
| # fallback للذاكرة | |
| _mem_cache[key] = (value, time.time() + ttl) | |
| # تنظيف الكاش القديم إذا كبر | |
| if len(_mem_cache) > 500: | |
| now = time.time() | |
| expired = [k for k, (_, exp) in _mem_cache.items() if now > exp] | |
| for k in expired: | |
| _mem_cache.pop(k, None) | |
| return True | |
| def cache_delete(key: str) -> bool: | |
| r = get_redis() | |
| if r: | |
| try: | |
| r.delete(key) | |
| except Exception: | |
| pass | |
| _mem_cache.pop(key, None) | |
| return True | |
| def cache_exists(key: str) -> bool: | |
| return cache_get(key) is not None | |