mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-24 03:54:21 +01:00
NUT-19: Cached Requests and Responses (#624)
* 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>
This commit is contained in:
67
cashu/mint/cache.py
Normal file
67
cashu/mint/cache.py
Normal file
@@ -0,0 +1,67 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user