youtube-summarizer/backend/services/mock_cache.py

77 lines
2.5 KiB
Python

from typing import Optional, Dict, Any
import json
from datetime import datetime, timedelta
import asyncio
class MockCacheClient:
"""Mock cache client that simulates Redis behavior in memory"""
def __init__(self):
self._cache: Dict[str, Dict[str, Any]] = {}
async def get(self, key: str) -> Optional[str]:
"""Get value from cache if not expired"""
await asyncio.sleep(0.01) # Simulate network delay
if key in self._cache:
entry = self._cache[key]
if entry['expires_at'] > datetime.utcnow():
return entry['value']
else:
# Remove expired entry
del self._cache[key]
return None
async def set(self, key: str, value: Any, ttl: int = 86400) -> bool:
"""Set value in cache with TTL in seconds"""
await asyncio.sleep(0.01) # Simulate network delay
self._cache[key] = {
'value': json.dumps(value) if not isinstance(value, str) else value,
'expires_at': datetime.utcnow() + timedelta(seconds=ttl),
'created_at': datetime.utcnow()
}
return True
async def setex(self, key: str, ttl: int, value: Any) -> bool:
"""Set with explicit TTL (Redis compatibility)"""
return await self.set(key, value, ttl)
async def delete(self, key: str) -> bool:
"""Delete key from cache"""
if key in self._cache:
del self._cache[key]
return True
return False
async def exists(self, key: str) -> bool:
"""Check if key exists and is not expired"""
if key in self._cache:
entry = self._cache[key]
if entry['expires_at'] > datetime.utcnow():
return True
else:
del self._cache[key]
return False
def clear_all(self):
"""Clear entire cache (for testing)"""
self._cache.clear()
def get_stats(self) -> Dict[str, Any]:
"""Get cache statistics"""
total_keys = len(self._cache)
expired_keys = sum(
1 for entry in self._cache.values()
if entry['expires_at'] <= datetime.utcnow()
)
return {
'total_keys': total_keys,
'active_keys': total_keys - expired_keys,
'expired_keys': expired_keys,
'cache_size_bytes': sum(
len(entry['value']) for entry in self._cache.values()
)
}