Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for caching non-FastAPI functions #66

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 52 additions & 3 deletions src/fastapi_redis_cache/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@
)


def cache(*, expire: Union[int, timedelta] = ONE_YEAR_IN_SECONDS):
def cache(*, expire: Union[int, timedelta] = ONE_YEAR_IN_SECONDS, fastapi_route: bool = True):
"""Enable caching behavior for the decorated function.

Args:
expire (Union[int, timedelta], optional): The number of seconds
from now when the cached response should expire. Defaults to 31,536,000
seconds (i.e., the number of seconds in one year).
fastapi_route (bool): True if this is caching a FastAPI route function or
False if caching a standard Python function.
"""

def outer_wrapper(func):
def fastapi_route_wrapper(func):
@wraps(func)
async def inner_wrapper(*args, **kwargs):
"""Return cached value if one exists, otherwise evaluate the wrapped function and cache the result."""
Expand Down Expand Up @@ -80,7 +82,54 @@ async def inner_wrapper(*args, **kwargs):

return inner_wrapper

return outer_wrapper
def standard_wrapper(func):
@wraps(func)
async def inner_wrapper_async(*args, **kwargs):
"""Return cached value if one exists, otherwise evaluate the wrapped function and cache the result."""

func_kwargs = kwargs.copy()
redis_cache = FastApiRedisCache()
if redis_cache.not_connected:
# if the redis client is not connected or request is not cacheable, no caching behavior is performed.
return await func(*args, **kwargs)
key = redis_cache.get_cache_key(func, *args, **kwargs)
ttl, in_cache = redis_cache.check_cache(key)
if in_cache:
return deserialize_json(in_cache)

response_data = await func(*args, **kwargs)
ttl = calculate_ttl(expire)
redis_cache.add_to_cache(key, response_data, ttl)
return response_data

@wraps(func)
def inner_wrapper_sync(*args, **kwargs):
"""Return cached value if one exists, otherwise evaluate the wrapped function and cache the result."""

func_kwargs = kwargs.copy()
redis_cache = FastApiRedisCache()
if redis_cache.not_connected:
# if the redis client is not connected or request is not cacheable, no caching behavior is performed.
return func(*args, **kwargs)
key = redis_cache.get_cache_key(func, *args, **kwargs)
ttl, in_cache = redis_cache.check_cache(key)
if in_cache:
return deserialize_json(in_cache)

response_data = func(*args, **kwargs)
ttl = calculate_ttl(expire)
redis_cache.add_to_cache(key, response_data, ttl)
return response_data

if asyncio.iscoroutinefunction(func):
return inner_wrapper_async
else:
return inner_wrapper_sync

if fastapi_route:
return fastapi_route_wrapper
else:
return standard_wrapper


async def get_api_response_async(func, *args, **kwargs):
Expand Down