mirror of
https://github.com/long2ice/fastapi-cache.git
synced 2026-03-24 20:47:54 +00:00
Add in-memory support.
This commit is contained in:
@@ -1,11 +1,17 @@
|
||||
class FastAPICache:
|
||||
_backend = None
|
||||
_prefix = None
|
||||
_expire = None
|
||||
_init = False
|
||||
|
||||
@classmethod
|
||||
def init(cls, backend, prefix: str = ""):
|
||||
def init(cls, backend, prefix: str = "", expire: int = None):
|
||||
if cls._init:
|
||||
return
|
||||
cls._init = True
|
||||
cls._backend = backend
|
||||
cls._prefix = prefix
|
||||
cls._expire = expire
|
||||
|
||||
@classmethod
|
||||
def get_backend(cls):
|
||||
@@ -14,5 +20,8 @@ class FastAPICache:
|
||||
|
||||
@classmethod
|
||||
def get_prefix(cls):
|
||||
assert cls._prefix, "You must call init first!" # nosec: B101
|
||||
return cls._prefix
|
||||
|
||||
@classmethod
|
||||
def get_expire(cls):
|
||||
return cls._expire
|
||||
|
||||
46
fastapi_cache/backends/inmemory.py
Normal file
46
fastapi_cache/backends/inmemory.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from threading import Lock
|
||||
from typing import Dict, Optional, Tuple
|
||||
|
||||
from fastapi_cache.backends import Backend
|
||||
|
||||
|
||||
@dataclass
|
||||
class Value:
|
||||
data: str
|
||||
ttl_ts: int
|
||||
|
||||
|
||||
class InMemoryBackend(Backend):
|
||||
_store: Dict[str, Value] = {}
|
||||
_lock = Lock()
|
||||
|
||||
@property
|
||||
def _now(self) -> int:
|
||||
return int(time.time())
|
||||
|
||||
def _get(self, key: str):
|
||||
v = self._store.get(key)
|
||||
if v:
|
||||
if v.ttl_ts < self._now:
|
||||
del self._store[key]
|
||||
else:
|
||||
return v
|
||||
|
||||
async def get_with_ttl(self, key: str) -> Tuple[int, Optional[str]]:
|
||||
with self._lock:
|
||||
v = self._get(key)
|
||||
if v:
|
||||
return v.ttl_ts - self._now, v.data
|
||||
return 0, None
|
||||
|
||||
async def get(self, key: str) -> str:
|
||||
with self._lock:
|
||||
v = self._get(key)
|
||||
if v:
|
||||
return v.data
|
||||
|
||||
async def set(self, key: str, value: str, expire: int = None):
|
||||
with self._lock:
|
||||
self._store[key] = Value(value, self._now + expire)
|
||||
@@ -39,45 +39,19 @@ def cache(
|
||||
def wrapper(func):
|
||||
@wraps(func)
|
||||
async def inner(*args, **kwargs):
|
||||
request = kwargs.get("request")
|
||||
backend = FastAPICache.get_backend()
|
||||
cache_key = key_builder(func, namespace, *args, **kwargs)
|
||||
ret = await backend.get(cache_key)
|
||||
if ret is not None:
|
||||
return coder.decode(ret)
|
||||
ttl, ret = await backend.get_with_ttl(cache_key)
|
||||
if not request:
|
||||
if ret is not None:
|
||||
return coder.decode(ret)
|
||||
ret = await func(*args, **kwargs)
|
||||
await backend.set(cache_key, coder.encode(ret), expire or FastAPICache.get_expire())
|
||||
return ret
|
||||
|
||||
ret = await func(*args, **kwargs)
|
||||
await backend.set(cache_key, coder.encode(ret), expire)
|
||||
return ret
|
||||
|
||||
return inner
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def cache_response(
|
||||
expire: int = None,
|
||||
coder: Type[Coder] = JsonCoder,
|
||||
key_builder: Callable = default_key_builder,
|
||||
namespace: Optional[str] = "",
|
||||
):
|
||||
"""
|
||||
cache fastapi response
|
||||
:param namespace:
|
||||
:param expire:
|
||||
:param coder:
|
||||
:param key_builder:
|
||||
:return:
|
||||
"""
|
||||
|
||||
def wrapper(func):
|
||||
@wraps(func)
|
||||
async def inner(request: Request, *args, **kwargs):
|
||||
if request.method != "GET":
|
||||
return await func(request, *args, **kwargs)
|
||||
|
||||
backend = FastAPICache.get_backend()
|
||||
cache_key = key_builder(func, namespace, request, *args, **kwargs)
|
||||
ttl, ret = await backend.get_with_ttl(cache_key)
|
||||
if_none_match = request.headers.get("if-none-match")
|
||||
if ret is not None:
|
||||
response = kwargs.get("response")
|
||||
@@ -90,8 +64,8 @@ def cache_response(
|
||||
response.headers["ETag"] = etag
|
||||
return coder.decode(ret)
|
||||
|
||||
ret = await func(request, *args, **kwargs)
|
||||
await backend.set(cache_key, coder.encode(ret), expire)
|
||||
ret = await func(*args, **kwargs)
|
||||
await backend.set(cache_key, coder.encode(ret), expire or FastAPICache.get_expire())
|
||||
return ret
|
||||
|
||||
return inner
|
||||
|
||||
Reference in New Issue
Block a user