sahamsense-api / app /cache /redis_cache.py
Immanuel Partogi Pardede
clean deploy: SahamSense API
d734ab2
Raw
History Blame Contribute Delete
2.6 kB
# app/cache/redis_cache.py
"""
Redis cache wrapper — dengan graceful fallback ke in-memory
"""
import json
import time
from typing import Any, Optional
from loguru import logger
try:
import redis.asyncio as redis
REDIS_AVAILABLE = True
except ImportError:
REDIS_AVAILABLE = False
class CacheLayer:
"""
Primary: Redis
Fallback: in-memory dict (development / jika Redis down)
"""
def __init__(self, redis_url: Optional[str] = None):
self._redis: Optional[redis.Redis] = None
self._memory: dict[str, tuple[Any, float]] = {} # (value, expire_at)
self._use_redis = False
if REDIS_AVAILABLE and redis_url:
try:
self._redis = redis.from_url(redis_url)
self._use_redis = True
logger.info("Cache: Redis aktif")
except Exception as e:
logger.warning(f"Redis gagal, fallback ke memory: {e}")
async def get(self, key: str) -> Optional[Any]:
if self._use_redis:
try:
val = await self._redis.get(key)
return json.loads(val) if val else None
except Exception:
pass
# Memory fallback
entry = self._memory.get(key)
if entry:
value, expire_at = entry
if time.time() < expire_at:
return value
del self._memory[key]
return None
async def set(
self,
key: str,
value: Any,
ttl: int = 3600
) -> None:
serialized = json.dumps(value, default=str)
if self._use_redis:
try:
await self._redis.setex(key, ttl, serialized)
return
except Exception:
pass
# Memory fallback
self._memory[key] = (value, time.time() + ttl)
async def delete(self, key: str) -> None:
if self._use_redis:
try:
await self._redis.delete(key)
return
except Exception:
pass
self._memory.pop(key, None)
def make_key(self, *parts: str) -> str:
return ":".join(parts)
# TTL Constants
TTL = {
"price": 300, # 5 menit
"news": 1800, # 30 menit
"sentiment": 1800,
"prediction": 3600, # 1 jam
"fundamental": 86400, # 24 jam
}
# Singleton
_cache: Optional[CacheLayer] = None
def get_cache(redis_url: Optional[str] = None) -> CacheLayer:
global _cache
if _cache is None:
_cache = CacheLayer(redis_url)
return _cache