Files
nutshell/cashu/mint/cache.py
lollerfirst 399c201552 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>
2024-12-03 16:03:01 +03:00

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()