mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-21 19:14:19 +01:00
* fast-api-cache setup * testing the cache * fix * still not working * asynccontextmanager * move test * use redis & custom caching setup (like CDK) * make format * poetry lock * fix format string + log when a cached response is found * log when a cahced response is found * fix tests * poetry lock * try tests on github * use docker compose * maybe we dont need docker * fix types * create_task instead of run * how about we start postgres * mint features * format * remove deprecated setex call * use global expiry for all cached routes * refactor feature map and set default to 1 week * refactor feature construction * Cache NUT-19 --------- Co-authored-by: callebtc <93376500+callebtc@users.noreply.github.com>
68 lines
2.3 KiB
Python
68 lines
2.3 KiB
Python
import asyncio
|
|
import functools
|
|
import json
|
|
|
|
from fastapi import Request
|
|
from loguru import logger
|
|
from pydantic import BaseModel
|
|
from redis.asyncio import from_url
|
|
from redis.exceptions import ConnectionError
|
|
|
|
from ..core.errors import CashuError
|
|
from ..core.settings import settings
|
|
|
|
|
|
class RedisCache:
|
|
expiry = settings.mint_redis_cache_ttl
|
|
|
|
def __init__(self):
|
|
if settings.mint_redis_cache_enabled:
|
|
if settings.mint_redis_cache_url is None:
|
|
raise CashuError("Redis cache url not provided")
|
|
self.redis = from_url(settings.mint_redis_cache_url)
|
|
asyncio.create_task(self.test_connection())
|
|
|
|
async def test_connection(self):
|
|
# PING
|
|
try:
|
|
await self.redis.ping()
|
|
logger.success("Connected to Redis caching server.")
|
|
except ConnectionError as e:
|
|
logger.error("Redis connection error.")
|
|
raise e
|
|
|
|
def cache(self):
|
|
def passthrough(func):
|
|
@functools.wraps(func)
|
|
async def wrapper(*args, **kwargs):
|
|
logger.trace(f"cache wrapper on route {func.__name__}")
|
|
result = await func(*args, **kwargs)
|
|
return result
|
|
|
|
return wrapper
|
|
|
|
def decorator(func):
|
|
@functools.wraps(func)
|
|
async def wrapper(request: Request, payload: BaseModel):
|
|
logger.trace(f"cache wrapper on route {func.__name__}")
|
|
key = request.url.path + payload.json()
|
|
logger.trace(f"KEY: {key}")
|
|
# Check if we have a value under this key
|
|
if await self.redis.exists(key):
|
|
logger.trace("Returning a cached response...")
|
|
resp = await self.redis.get(key)
|
|
if resp:
|
|
return json.loads(resp)
|
|
else:
|
|
raise Exception(f"Found no cached response for key {key}")
|
|
result = await func(request, payload)
|
|
await self.redis.set(name=key, value=result.json(), ex=self.expiry)
|
|
return result
|
|
|
|
return wrapper
|
|
|
|
return passthrough if not settings.mint_redis_cache_enabled else decorator
|
|
|
|
async def disconnect(self):
|
|
await self.redis.close()
|