mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 13:15:43 +00:00 
			
		
		
		
	Skip ready functions if not in main thread or plugins are not loaded yet
This commit is contained in:
		| @@ -14,7 +14,8 @@ from django.db.utils import IntegrityError | ||||
| import InvenTree.conversion | ||||
| import InvenTree.tasks | ||||
| from InvenTree.config import get_setting | ||||
| from InvenTree.ready import canAppAccessDatabase, isInTestMode | ||||
| from InvenTree.ready import (canAppAccessDatabase, isInMainThread, | ||||
|                              isInTestMode, isPluginRegistryLoaded) | ||||
|  | ||||
| logger = logging.getLogger("inventree") | ||||
|  | ||||
| @@ -34,6 +35,10 @@ class InvenTreeConfig(AppConfig): | ||||
|         - Collecting notification methods | ||||
|         - Adding users set in the current environment | ||||
|         """ | ||||
|         # skip loading if plugins are not loaded or we run in a background thread | ||||
|         if not isPluginRegistryLoaded() or not isInMainThread(): | ||||
|             return | ||||
|  | ||||
|         if canAppAccessDatabase() or settings.TESTING_ENV: | ||||
|             InvenTree.tasks.check_for_migrations(worker=False) | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| """Functions to check if certain parts of InvenTree are ready.""" | ||||
|  | ||||
| import os | ||||
| import sys | ||||
|  | ||||
|  | ||||
| @@ -13,6 +14,20 @@ def isImportingData(): | ||||
|     return 'loaddata' in sys.argv | ||||
|  | ||||
|  | ||||
| def isInMainThread(): | ||||
|     """Django starts two processes, one for the actual dev server and the other to reload the application. | ||||
|  | ||||
|     - The RUN_MAIN env is set in that case. However if --noreload is applied, this variable | ||||
|     is not set because there are no different threads. | ||||
|     - If this app is run in gunicorn there are several threads having "equal rights" so there is no real | ||||
|     main thread so we skip this check | ||||
|     """ | ||||
|     if '--noreload' in sys.argv or "gunicorn" in os.environ.get("SERVER_SOFTWARE", ""): | ||||
|         return True | ||||
|  | ||||
|     return os.environ.get('RUN_MAIN', None) == 'true' | ||||
|  | ||||
|  | ||||
| def canAppAccessDatabase(allow_test: bool = False, allow_plugins: bool = False, allow_shell: bool = False): | ||||
|     """Returns True if the apps.py file can access database records. | ||||
|  | ||||
| @@ -60,3 +75,21 @@ def canAppAccessDatabase(allow_test: bool = False, allow_plugins: bool = False, | ||||
|             return False | ||||
|  | ||||
|     return True | ||||
|  | ||||
|  | ||||
| def isPluginRegistryLoaded(): | ||||
|     """The plugin registry reloads all apps onetime after starting so that the discovered AppConfigs are added to Django. | ||||
|  | ||||
|     This triggers the ready function of AppConfig to execute twice. Add this check to prevent from running two times. | ||||
|  | ||||
|     Returns: 'False' if the apps have not been reloaded already to prevent running the ready function twice | ||||
|     """ | ||||
|     from django.conf import settings | ||||
|  | ||||
|     # If plugins are not enabled, there won't be a second load | ||||
|     if not settings.PLUGINS_ENABLED: | ||||
|         return True | ||||
|  | ||||
|     from plugin import registry | ||||
|  | ||||
|     return not registry.is_loading | ||||
|   | ||||
| @@ -12,7 +12,8 @@ from django.conf import settings | ||||
| from django.core.exceptions import AppRegistryNotReady | ||||
| from django.db.utils import OperationalError | ||||
|  | ||||
| from InvenTree.ready import canAppAccessDatabase | ||||
| from InvenTree.ready import (canAppAccessDatabase, isInMainThread, | ||||
|                              isPluginRegistryLoaded) | ||||
|  | ||||
| logger = logging.getLogger("inventree") | ||||
|  | ||||
| @@ -35,6 +36,10 @@ class LabelConfig(AppConfig): | ||||
|  | ||||
|     def ready(self): | ||||
|         """This function is called whenever the label app is loaded.""" | ||||
|         # skip loading if plugins are not loaded or we run in a background thread | ||||
|         if not isPluginRegistryLoaded() or not isInMainThread(): | ||||
|             return | ||||
|  | ||||
|         if canAppAccessDatabase(): | ||||
|  | ||||
|             try: | ||||
|   | ||||
| @@ -5,7 +5,8 @@ import logging | ||||
| from django.apps import AppConfig | ||||
| from django.db.utils import OperationalError, ProgrammingError | ||||
|  | ||||
| from InvenTree.ready import canAppAccessDatabase, isImportingData | ||||
| from InvenTree.ready import (canAppAccessDatabase, isImportingData, | ||||
|                              isInMainThread, isPluginRegistryLoaded) | ||||
|  | ||||
| logger = logging.getLogger("inventree") | ||||
|  | ||||
| @@ -16,6 +17,10 @@ class PartConfig(AppConfig): | ||||
|  | ||||
|     def ready(self): | ||||
|         """This function is called whenever the Part app is loaded.""" | ||||
|         # skip loading if plugins are not loaded or we run in a background thread | ||||
|         if not isPluginRegistryLoaded() or not isInMainThread(): | ||||
|             return | ||||
|  | ||||
|         if canAppAccessDatabase(): | ||||
|             self.update_trackable_status() | ||||
|             self.reset_part_pricing_flags() | ||||
|   | ||||
| @@ -10,7 +10,7 @@ from django.apps import AppConfig | ||||
|  | ||||
| from maintenance_mode.core import set_maintenance_mode | ||||
|  | ||||
| from InvenTree.ready import canAppAccessDatabase | ||||
| from InvenTree.ready import canAppAccessDatabase, isInMainThread | ||||
| from plugin import registry | ||||
|  | ||||
| logger = logging.getLogger('inventree') | ||||
| @@ -23,6 +23,10 @@ class PluginAppConfig(AppConfig): | ||||
|  | ||||
|     def ready(self): | ||||
|         """The ready method is extended to initialize plugins.""" | ||||
|         # skip loading if we run in a background thread | ||||
|         if not isInMainThread(): | ||||
|             return | ||||
|  | ||||
|         if not canAppAccessDatabase(allow_test=True, allow_plugins=True): | ||||
|             logger.info("Skipping plugin loading sequence")  # pragma: no cover | ||||
|         else: | ||||
|   | ||||
| @@ -18,7 +18,12 @@ class ReportConfig(AppConfig): | ||||
|     def ready(self): | ||||
|         """This function is called whenever the report app is loaded.""" | ||||
|  | ||||
|         from InvenTree.ready import canAppAccessDatabase | ||||
|         from InvenTree.ready import (canAppAccessDatabase, isInMainThread, | ||||
|                                      isPluginRegistryLoaded) | ||||
|  | ||||
|         # skip loading if plugins are not loaded or we run in a background thread | ||||
|         if not isPluginRegistryLoaded() or not isInMainThread(): | ||||
|             return | ||||
|  | ||||
|         # Configure logging for PDF generation (disable "info" messages) | ||||
|         logging.getLogger('fontTools').setLevel(logging.WARNING) | ||||
|   | ||||
| @@ -5,7 +5,8 @@ import logging | ||||
| from django.apps import AppConfig | ||||
| from django.db.utils import OperationalError, ProgrammingError | ||||
|  | ||||
| from InvenTree.ready import canAppAccessDatabase | ||||
| from InvenTree.ready import (canAppAccessDatabase, isInMainThread, | ||||
|                              isPluginRegistryLoaded) | ||||
|  | ||||
| logger = logging.getLogger('inventree') | ||||
|  | ||||
| @@ -17,6 +18,11 @@ class UsersConfig(AppConfig): | ||||
|  | ||||
|     def ready(self): | ||||
|         """Called when the 'users' app is loaded at runtime""" | ||||
|  | ||||
|         # skip loading if plugins are not loaded or we run in a background thread | ||||
|         if not isPluginRegistryLoaded() or not isInMainThread(): | ||||
|             return | ||||
|  | ||||
|         if canAppAccessDatabase(allow_test=True): | ||||
|  | ||||
|             try: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user