Files
Aurora-Core/app/services/cache.py
T
NixReaperandClaude Sonnet 5 c20df1c503
CI / lint (push) Canceled after 0s
CI / typecheck (push) Canceled after 0s
CI / unit-tests (push) Canceled after 0s
CI / integration-tests (push) Canceled after 0s
CI / container-build (push) Canceled after 0s
CI / dependency-audit (push) Canceled after 0s
Initial Aurora Core 0.1 implementation
Production-grade media metadata backend per docs/aurora-core-spec.md:
Aurora-owned UUIDv7 identity system, normalized movie/TV/people/credits
schema, provider abstraction with a TMDb adapter, an idempotent async
ingestion pipeline (normalize -> match -> upsert -> provenance), a
Postgres FTS/trigram search layer, a stateless FastAPI v1 API with
Redis caching/rate-limiting, arq workers, dev/prod Docker Compose
topologies, unit + integration + load tests, CI, and architecture/
database/API/ERD documentation.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-09-04 17:34:03 -05:00

62 lines
1.5 KiB
Python

"""Cache abstraction over Redis (section 21).
Redis is disposable acceleration — every function here fails open: if Redis
is unreachable, reads report a cache miss and writes are silently skipped,
so the API keeps serving from PostgreSQL instead of failing.
"""
from __future__ import annotations
import orjson
from redis.asyncio import Redis
from app.core.config import get_settings
settings = get_settings()
CACHE_VERSION = "v1"
def build_key(*parts: str) -> str:
return ":".join(("aurora", CACHE_VERSION, *parts))
async def cache_get_json(redis: Redis, key: str) -> dict | list | None:
try:
raw = await redis.get(key)
except Exception:
return None
if raw is None:
return None
try:
return orjson.loads(raw)
except orjson.JSONDecodeError:
return None
async def cache_set_json(
redis: Redis, key: str, value: dict | list, ttl: int | None = None
) -> None:
ttl = ttl if ttl is not None else settings.CACHE_DEFAULT_TTL
try:
await redis.set(key, orjson.dumps(value), ex=ttl)
except Exception:
return
async def cache_delete(redis: Redis, *keys: str) -> None:
if not keys:
return
try:
await redis.delete(*keys)
except Exception:
return
async def cache_delete_prefix(redis: Redis, prefix: str) -> None:
try:
async for key in redis.scan_iter(match=f"{prefix}*"):
await redis.delete(key)
except Exception:
return