You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

88 lines
2.6 KiB

import json
import time
import asyncio
from typing import Any
from redis.asyncio import Redis
from config import settings
class CacheManager:
def __init__(self):
self._local: dict[str, tuple[float, Any]] = {}
self._redis: Redis | None = None
self._redis_available = False
self._lock = asyncio.Lock()
async def connect(self):
try:
self._redis = Redis.from_url(settings.REDIS_URL, decode_responses=True)
await self._redis.ping()
self._redis_available = True
except Exception:
self._redis_available = False
async def disconnect(self):
if self._redis:
await self._redis.close()
@property
def available(self) -> bool:
return self._redis_available
async def get(self, key: str) -> Any | None:
if self._redis_available and self._redis:
try:
val = await self._redis.get(key)
if val:
return json.loads(val)
except Exception:
pass
async with self._lock:
entry = self._local.get(key)
if entry:
expire_at, value = entry
if time.time() < expire_at:
return value
del self._local[key]
return None
async def set(self, key: str, value: Any, ttl: int = 300):
if self._redis_available and self._redis:
try:
await self._redis.setex(key, ttl, json.dumps(value, default=str))
except Exception:
pass
async with self._lock:
self._local[key] = (time.time() + ttl, value)
if len(self._local) > 10000:
now = time.time()
expired = [k for k, (t, v) in self._local.items() if now >= t]
for k in expired:
del self._local[k]
async def delete(self, key: str):
if self._redis_available and self._redis:
try:
await self._redis.delete(key)
except Exception:
pass
async with self._lock:
self._local.pop(key, None)
async def delete_pattern(self, pattern: str):
if self._redis_available and self._redis:
try:
keys = await self._redis.keys(pattern)
if keys:
await self._redis.delete(*keys)
except Exception:
pass
async with self._lock:
to_delete = [k for k in self._local if pattern.replace("*", "") in k]
for k in to_delete:
del self._local[k]
cache_manager = CacheManager()