2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-11-30 09:20:03 +00:00

Implement caching for unit registry: (#10870)

* Implement caching for unit registry:

- Registry could become out of sync across sessions
- Implement a simple caching system

* Simplify code
This commit is contained in:
Oliver
2025-11-20 22:31:33 +11:00
committed by GitHub
parent f72efb804e
commit 835c7784f9

View File

@@ -2,30 +2,76 @@
import logging
import re
from hashlib import md5
from typing import Optional
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
import pint
_unit_registry = None
import structlog
from common.settings import get_global_setting, set_global_setting
from InvenTree.cache import get_session_cache, set_session_cache
_UNIT_REG_CACHE_KEY = 'unit_registry_hash'
_unit_registry = None
_unit_registry_hash: str = ''
logger = structlog.get_logger('inventree')
# Disable log output for Pint library
logging.getLogger('pint').setLevel(logging.ERROR)
def get_unit_registry_hash():
"""Return a hash representing the current state of the unit registry.
We use this to determine if we need to reload the unit registry,
due to changes in the database.
"""
# Look in the session cache first (faster, and potentially newer)
registry_hash = get_session_cache(_UNIT_REG_CACHE_KEY)
if registry_hash is None:
registry_hash = get_global_setting(
'_UNIT_REGISTRY_HASH', create=False, backup_value=''
)
if registry_hash:
set_session_cache(_UNIT_REG_CACHE_KEY, registry_hash)
return registry_hash
def set_unit_registry_hash(registry_hash: str):
"""Save the hash representing the current state of the unit registry.
Because most of the registry is static, we only need to consider the
CustomUnit entries in the database.
"""
global _unit_registry_hash
_unit_registry_hash = registry_hash
# Save to both the global settings and the session cache
set_global_setting('_UNIT_REGISTRY_HASH', registry_hash)
set_session_cache(_UNIT_REG_CACHE_KEY, registry_hash)
def get_unit_registry():
"""Return a custom instance of the Pint UnitRegistry."""
global _unit_registry
global _unit_registry_hash
# Cache the unit registry for speedier access
if _unit_registry is None:
return reload_unit_registry()
# Check if the unit registry has changed
if _unit_registry_hash != get_unit_registry_hash():
logger.info('Unit registry hash has changed, reloading unit registry')
return reload_unit_registry()
return _unit_registry
@@ -60,9 +106,16 @@ def reload_unit_registry():
try:
from common.models import CustomUnit
# Calculate a hash of all custom units
hash_md5 = md5()
for cu in CustomUnit.objects.all():
try:
reg.define(cu.fmt_string())
fmt = cu.fmt_string()
reg.define(fmt)
hash_md5.update(fmt.encode('utf-8'))
except Exception as e:
logger.exception(
'Failed to load custom unit: %s - %s', cu.fmt_string(), e
@@ -71,6 +124,9 @@ def reload_unit_registry():
# Once custom units are loaded, save registry
_unit_registry = reg
# Update the unit registry hash
set_unit_registry_hash(hash_md5.hexdigest())
except Exception:
# Database is not ready, or CustomUnit model is not available
pass