feat: frappe.utils.caching.site_cache
Decorator to cache method calls across requests. The cache is stored in
frappe.utils.caching._SITE_CACHE. The cache persists on the parent process.
It offers a light-weight cache for the current process without the additional
overhead of serializing / deserializing Python objects.
Note: This cache isn't shared among workers. If you need to share data across
workers, use redis (frappe.cache API) instead.
Usage:
from frappe.utils.caching import site_cache
@site_cache
def calculate_pi():
import math, time
precision = get_precision("Math Constant", "Pi") # depends on
site data
return round(math.pi, precision)
calculate_pi(10) # will calculate value
calculate_pi(10) # will return value from cache
calculate_pi.clear_cache() # clear this function's cache for all sites
calculate_pi(10) # will calculate value
This commit is contained in:
parent
db9b0d3d4f
commit
3be3b83c4f
1 changed files with 53 additions and 3 deletions
|
|
@ -2,17 +2,21 @@
|
|||
# License: MIT. Check LICENSE
|
||||
|
||||
import json
|
||||
from collections import defaultdict
|
||||
from functools import wraps
|
||||
from typing import Callable, Dict, Tuple
|
||||
|
||||
import frappe
|
||||
|
||||
_SITE_CACHE = defaultdict(lambda: defaultdict(dict))
|
||||
|
||||
def __generate_key(func, args, kwargs):
|
||||
|
||||
def __generate_request_cache_key(func: Callable, args: Tuple, kwargs: Dict):
|
||||
"""Generate a key for the cache."""
|
||||
return f"{func.__module__}.{func.__name__}{json.dumps((args, kwargs))}"
|
||||
|
||||
|
||||
def request_cache(func):
|
||||
def request_cache(func: Callable) -> Callable:
|
||||
"""Decorator to cache function calls mid-request. Cache is stored in
|
||||
frappe.local.request_cache. The cache only persists for the current request
|
||||
and is cleared when the request is over. The function is called just once
|
||||
|
|
@ -42,7 +46,7 @@ def request_cache(func):
|
|||
logger = frappe.logger(module=__name__)
|
||||
|
||||
try:
|
||||
key = __generate_key(func, args, kwargs)
|
||||
key = __generate_request_cache_key(func, args, kwargs)
|
||||
except Exception:
|
||||
logger.warning(f"request_cache: Couldn't generate key for args: {args}, kwargs: {kwargs}")
|
||||
return func(*args, **kwargs)
|
||||
|
|
@ -54,3 +58,49 @@ def request_cache(func):
|
|||
return frappe.local.request_cache[key]
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def site_cache(func: Callable) -> Callable:
|
||||
"""Decorator to cache method calls across requests. The cache is stored in
|
||||
frappe.utils.caching._SITE_CACHE. The cache persists on the parent process.
|
||||
It offers a light-weight cache for the current process without the additional
|
||||
overhead of serializing / deserializing Python objects.
|
||||
|
||||
Note: This cache isn't shared among workers. If you need to share data across
|
||||
workers, use redis (frappe.cache API) instead.
|
||||
|
||||
Usage:
|
||||
from frappe.utils.caching import site_cache
|
||||
|
||||
@site_cache
|
||||
def calculate_pi():
|
||||
import math, time
|
||||
precision = get_precision("Math Constant", "Pi") # depends on site data
|
||||
return round(math.pi, precision)
|
||||
|
||||
calculate_pi(10) # will calculate value
|
||||
calculate_pi(10) # will return value from cache
|
||||
calculate_pi.clear_cache() # clear this function's cache for all sites
|
||||
calculate_pi(10) # will calculate value
|
||||
"""
|
||||
func_key = f"{func.__module__}.{func.__name__}"
|
||||
|
||||
def clear_cache():
|
||||
"""Clear cache for this function for all sites if not specified."""
|
||||
_SITE_CACHE[func_key].clear()
|
||||
|
||||
func.clear_cache = clear_cache
|
||||
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
if getattr(frappe.local, "initialised", None):
|
||||
func_call_key = json.dumps((args, kwargs))
|
||||
|
||||
if func_call_key not in _SITE_CACHE[func_key][frappe.local.site]:
|
||||
_SITE_CACHE[func_key][frappe.local.site][func_call_key] = func(*args, **kwargs)
|
||||
|
||||
return _SITE_CACHE[func_key][frappe.local.site][func_call_key]
|
||||
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue