2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-12-14 00:09:56 +00:00

App ready warning (#10938)

* Fix for currency functions

- Prevent database access until after the 'common' app has loaded

* Add decorator to selectively ignore warnings

* Add reference to PR

* Fix variable assignment

* Use functools.wraps

* Add wrapper for loading machine registry

* Move decorator to ready.py

* Add missing code

* Set backup values to match default currency codes

* Bump API version
This commit is contained in:
Oliver
2025-12-04 19:30:14 +11:00
committed by GitHub
parent 2ffc2cb9fc
commit c443b4e9b8
8 changed files with 105 additions and 22 deletions

View File

@@ -1,11 +1,15 @@
"""InvenTree API version information."""
# InvenTree API version
INVENTREE_API_VERSION = 428
INVENTREE_API_VERSION = 429
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
v429 -> 2025-12-04 : https://github.com/inventree/InvenTree/pull/10938
- Adjust default values for currency codes in the API schema
- Note that this does not change any functional behavior, only the schema documentation
v428 -> 2025-11-28 : https://github.com/inventree/InvenTree/pull/10926
- Various typo fixes in API - no functional changes

View File

@@ -18,6 +18,7 @@ import InvenTree.conversion
import InvenTree.ready
import InvenTree.tasks
from InvenTree.config import get_setting
from InvenTree.ready import ignore_ready_warning
logger = structlog.get_logger('inventree')
MIGRATIONS_CHECK_DONE = False
@@ -70,9 +71,7 @@ class InvenTreeConfig(AppConfig):
InvenTree.tasks.offload_task(InvenTree.tasks.check_for_migrations)
self.update_site_url()
# Ensure the unit registry is loaded
InvenTree.conversion.get_unit_registry()
self.load_unit_registry()
if InvenTree.ready.canAppAccessDatabase() or settings.TESTING_ENV:
self.add_user_on_startup()
@@ -84,6 +83,7 @@ class InvenTreeConfig(AppConfig):
social_account_updated.connect(sso.ensure_sso_groups)
@ignore_ready_warning
def remove_obsolete_tasks(self):
"""Delete any obsolete scheduled tasks in the database."""
obsolete = [
@@ -112,6 +112,7 @@ class InvenTreeConfig(AppConfig):
except Exception:
logger.exception('Failed to remove obsolete tasks - database not ready')
@ignore_ready_warning
def start_background_tasks(self):
"""Start all background tests for InvenTree."""
logger.info('Starting background tasks...')
@@ -171,6 +172,7 @@ class InvenTreeConfig(AppConfig):
logger.info('Started %s scheduled background tasks...', len(tasks))
@ignore_ready_warning
def add_heartbeat(self):
"""Ensure there is at least one background task in the queue."""
import django_q.models
@@ -185,6 +187,7 @@ class InvenTreeConfig(AppConfig):
except Exception:
pass
@ignore_ready_warning
def collect_tasks(self):
"""Collect all background tasks."""
for app_name, app in apps.app_configs.items():
@@ -197,6 +200,7 @@ class InvenTreeConfig(AppConfig):
except Exception as e: # pragma: no cover
logger.exception('Error loading tasks for %s: %s', app_name, e)
@ignore_ready_warning
def update_site_url(self):
"""Update the site URL setting.
@@ -223,6 +227,12 @@ class InvenTreeConfig(AppConfig):
except Exception:
pass
@ignore_ready_warning
def load_unit_registry(self):
"""Ensure the unit registry is loaded."""
InvenTree.conversion.get_unit_registry()
@ignore_ready_warning
def add_user_on_startup(self):
"""Add a user on startup."""
# stop if checks were already created
@@ -281,6 +291,7 @@ class InvenTreeConfig(AppConfig):
except IntegrityError:
logger.warning('The user "%s" could not be created', add_user)
@ignore_ready_warning
def add_user_from_file(self):
"""Add the superuser from a file."""
# stop if checks were already created

View File

@@ -1,8 +1,31 @@
"""Functions to check if certain parts of InvenTree are ready."""
import functools
import inspect
import os
import sys
import warnings
# Keep track of loaded apps, to prevent multiple executions of ready functions
_loaded_apps = set()
def clearLoadedApps():
"""Clear the set of loaded apps."""
global _loaded_apps
_loaded_apps = set()
def setAppLoaded(app_name: str):
"""Mark an app as loaded."""
global _loaded_apps
_loaded_apps.add(app_name)
def isAppLoaded(app_name: str) -> bool:
"""Return True if the app has been marked as loaded."""
global _loaded_apps
return app_name in _loaded_apps
def isInTestMode():
@@ -157,3 +180,22 @@ def isPluginRegistryLoaded():
from plugin import registry
return registry.plugins_loaded
def ignore_ready_warning(func):
"""Decorator to ignore 'AppRegistryNotReady' warnings in functions called during app ready phase.
Ref: https://github.com/inventree/InvenTree/issues/10806
"""
@functools.wraps(func)
def wrapper(*args, **kwargs):
with warnings.catch_warnings():
warnings.filterwarnings(
'ignore',
message='Accessing the database during app initialization is discouraged',
category=RuntimeWarning,
)
return func(*args, **kwargs)
return wrapper

View File

@@ -6,6 +6,7 @@ import structlog
import InvenTree.ready
from common.settings import get_global_setting, set_global_setting
from InvenTree.ready import ignore_ready_warning
logger = structlog.get_logger('inventree')
@@ -20,11 +21,16 @@ class CommonConfig(AppConfig):
def ready(self):
"""Initialize restart flag clearance on startup."""
from InvenTree.ready import setAppLoaded
setAppLoaded(self.name)
if InvenTree.ready.isRunningMigrations(): # pragma: no cover
return
self.clear_restart_flag()
@ignore_ready_warning
def clear_restart_flag(self):
"""Clear the SERVER_RESTART_REQUIRED setting."""
try:

View File

@@ -11,6 +11,7 @@ import structlog
from moneyed import CURRENCIES
import InvenTree.helpers
import InvenTree.ready
logger = structlog.get_logger('inventree')
@@ -19,15 +20,18 @@ def currency_code_default(create: bool = True):
"""Returns the default currency code (or USD if not specified)."""
from common.settings import get_global_setting
try:
code = get_global_setting(
'INVENTREE_DEFAULT_CURRENCY', create=create, cache=True
)
except Exception: # pragma: no cover
# Database may not yet be ready, no need to throw an error here
code = ''
code = ''
if code not in CURRENCIES:
if InvenTree.ready.isAppLoaded('common'):
try:
code = get_global_setting(
'INVENTREE_DEFAULT_CURRENCY', create=create, cache=True
)
except Exception: # pragma: no cover
# Database may not yet be ready, no need to throw an error here
code = ''
if not code or code not in CURRENCIES:
code = 'USD' # pragma: no cover
return code
@@ -47,9 +51,13 @@ def currency_codes() -> list:
"""Returns the current currency codes."""
from common.settings import get_global_setting
codes = get_global_setting(
'CURRENCY_CODES', create=False, environment_key='INVENTREE_CURRENCY_CODES'
).strip()
codes = None
# Ensure we do not hit the database until the common app is loaded
if InvenTree.ready.isAppLoaded('common'):
codes = get_global_setting(
'CURRENCY_CODES', create=False, environment_key='INVENTREE_CURRENCY_CODES'
).strip()
if not codes:
codes = currency_codes_default_list()

View File

@@ -7,6 +7,7 @@ import structlog
from InvenTree.ready import (
canAppAccessDatabase,
ignore_ready_warning,
isImportingData,
isInMainThread,
isPluginRegistryLoaded,
@@ -32,12 +33,17 @@ class MachineConfig(AppConfig):
logger.debug('Machine app: Skipping machine loading sequence')
return
from machine import registry
try:
logger.info('Loading InvenTree machines')
if not registry.is_ready:
registry.initialize(main=isInMainThread())
self.initialize_registry()
except (OperationalError, ProgrammingError):
# Database might not yet be ready
logger.warn('Database was not ready for initializing machines')
@ignore_ready_warning
def initialize_registry(self):
"""Initialize the machine registry."""
from machine import registry
if not registry.is_ready:
logger.info('Loading InvenTree machines')
registry.initialize(main=isInMainThread())

View File

@@ -9,7 +9,12 @@ from django.apps import AppConfig
import structlog
from maintenance_mode.core import set_maintenance_mode
from InvenTree.ready import canAppAccessDatabase, isInMainThread, isInWorkerThread
from InvenTree.ready import (
canAppAccessDatabase,
ignore_ready_warning,
isInMainThread,
isInWorkerThread,
)
from plugin import registry
logger = structlog.get_logger('inventree')
@@ -24,6 +29,7 @@ class PluginAppConfig(AppConfig):
"""The ready method is extended to initialize plugins."""
self.reload_plugin_registry()
@ignore_ready_warning
def reload_plugin_registry(self):
"""Reload the plugin registry."""
if not isInMainThread() and not isInWorkerThread():

View File

@@ -1466,7 +1466,7 @@ def schema(
'False' # Disable plugins to ensure they are kep out of schema
)
envs['INVENTREE_CURRENCY_CODES'] = (
'AUD,CNY,EUR,USD' # Default currency codes to ensure they are stable
'AUD,CAD,CNY,EUR,GBP,JPY,NZD,USD' # Default currency codes to ensure they are stable
)
manage(c, cmd, pty=True, env=envs)