mirror of
https://github.com/inventree/InvenTree.git
synced 2025-12-14 08:19:54 +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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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():
|
||||
|
||||
2
tasks.py
2
tasks.py
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user