FastApi-ISS/utils/seen_store.py

64 lines
2.0 KiB
Python

# utils/seen_store.py
import os, redis
from typing import Iterable, Optional
import logging
logger = logging.getLogger(__name__)
REDIS_URL = os.environ.get("REDIS_URL", "redis://localhost:6379/0")
_redis_client: Optional[redis.Redis] = None
def _get_redis_client() -> Optional[redis.Redis]:
"""Get Redis client with error handling"""
global _redis_client
if _redis_client is not None:
return _redis_client
try:
_redis_client = redis.from_url(REDIS_URL, decode_responses=True)
# Test the connection
_redis_client.ping()
logger.info("✅ Redis connection established")
return _redis_client
except Exception as e:
logger.warning(f"⚠️ Redis connection failed: {e}")
logger.warning("📝 Pagination will be disabled - posts may be duplicated")
_redis_client = None
return None
def seen_key(username: str) -> str:
return f"ig:seen:{username}"
def mark_seen(username: str, ids: Iterable[str]) -> None:
"""Mark posts as seen (Redis optional)"""
if not ids:
return
r = _get_redis_client()
if r is None:
return # Skip if Redis is not available
try:
r.sadd(seen_key(username), *ids)
except Exception as e:
logger.warning(f"⚠️ Failed to mark posts as seen: {e}")
def filter_unseen(username: str, ids: Iterable[str]) -> list[str]:
"""Filter out already seen posts (Redis optional)"""
r = _get_redis_client()
if r is None:
# If Redis is not available, return all IDs (no filtering)
return list(ids)
try:
# pipeline for speed
key = seen_key(username)
pipe = r.pipeline()
for i in ids:
pipe.sismember(key, i)
flags = pipe.execute()
return [i for i, seen in zip(ids, flags) if not seen]
except Exception as e:
logger.warning(f"⚠️ Failed to filter unseen posts: {e}")
# Fallback: return all IDs if Redis fails
return list(ids)