2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-07-01 11:10:54 +00:00

[bug] Fixes for plugin loading mechanism (#9826)

* Fix logic for registry mutex lock

* Handle potential errors during UsersConfig launch

* Remove debug statement

* Revert to_raise value

* Clear plugin errors on reload

* Better method of avoiding duplicates
This commit is contained in:
Oliver
2025-06-22 12:40:07 +10:00
committed by GitHub
parent 785bda26c4
commit 4d029b0d54
3 changed files with 24 additions and 4 deletions

View File

@ -88,7 +88,7 @@ class PluginsRegistry:
self.plugin_modules: list[InvenTreePlugin] = [] # Holds all discovered plugins self.plugin_modules: list[InvenTreePlugin] = [] # Holds all discovered plugins
self.mixin_modules: dict[str, Any] = {} # Holds all discovered mixins self.mixin_modules: dict[str, Any] = {} # Holds all discovered mixins
self.errors = {} # Holds discovering errors self.errors = {} # Holds errors discovered during loading
self.loading_lock = Lock() # Lock to prevent multiple loading at the same time self.loading_lock = Lock() # Lock to prevent multiple loading at the same time
@ -307,6 +307,7 @@ class PluginsRegistry:
full_reload: bool = False, full_reload: bool = False,
force_reload: bool = False, force_reload: bool = False,
collect: bool = False, collect: bool = False,
clear_errors: bool = False,
_internal: Optional[list] = None, _internal: Optional[list] = None,
): ):
"""Reload the plugin registry. """Reload the plugin registry.
@ -317,6 +318,7 @@ class PluginsRegistry:
full_reload (bool, optional): Reload everything - including plugin mechanism. Defaults to False. full_reload (bool, optional): Reload everything - including plugin mechanism. Defaults to False.
force_reload (bool, optional): Also reload base apps. Defaults to False. force_reload (bool, optional): Also reload base apps. Defaults to False.
collect (bool, optional): Collect plugins before reloading. Defaults to False. collect (bool, optional): Collect plugins before reloading. Defaults to False.
clear_errors (bool, optional): Clear any previous loading errors. Defaults to False.
_internal (list, optional): Internal apps to reload (used for testing). Defaults to None _internal (list, optional): Internal apps to reload (used for testing). Defaults to None
""" """
# Do not reload when currently loading # Do not reload when currently loading
@ -324,7 +326,15 @@ class PluginsRegistry:
logger.debug('Skipping reload - plugin registry is currently loading') logger.debug('Skipping reload - plugin registry is currently loading')
return return
if self.loading_lock.acquire(blocking=False): if not self.loading_lock.acquire(blocking=False):
logger.exception('Could not acquire lock for reload_plugins')
return
# Reset the loading error state
if clear_errors:
self.errors = {}
try:
logger.info( logger.info(
'Plugin Registry: Reloading plugins - Force: %s, Full: %s, Collect: %s', 'Plugin Registry: Reloading plugins - Force: %s, Full: %s, Collect: %s',
force_reload, force_reload,
@ -343,10 +353,15 @@ class PluginsRegistry:
self._load_plugins(full_reload=full_reload, _internal=_internal) self._load_plugins(full_reload=full_reload, _internal=_internal)
self.update_plugin_hash() self.update_plugin_hash()
self.loading_lock.release()
logger.info('Plugin Registry: Loaded %s plugins', len(self.plugins)) logger.info('Plugin Registry: Loaded %s plugins', len(self.plugins))
except Exception as e:
logger.exception('Expected error during plugin reload: %s', e)
finally:
# Ensure the lock is released always
self.loading_lock.release()
def plugin_dirs(self): def plugin_dirs(self):
"""Construct a list of directories from where plugins can be loaded.""" """Construct a list of directories from where plugins can be loaded."""
# Builtin plugins are *always* loaded # Builtin plugins are *always* loaded

View File

@ -213,6 +213,7 @@ class PluginReloadSerializer(serializers.Serializer):
full_reload=self.validated_data.get('full_reload', False), full_reload=self.validated_data.get('full_reload', False),
force_reload=self.validated_data.get('force_reload', False), force_reload=self.validated_data.get('force_reload', False),
collect=self.validated_data.get('collect_plugins', False), collect=self.validated_data.get('collect_plugins', False),
clear_errors=True,
) )

View File

@ -35,11 +35,15 @@ class UsersConfig(AppConfig):
rebuild_all_permissions() rebuild_all_permissions()
except (OperationalError, ProgrammingError): except (OperationalError, ProgrammingError):
pass pass
except Exception as e:
logger.exception('Failed to rebuild permissions: %s', e)
try: try:
self.update_owners() self.update_owners()
except (OperationalError, ProgrammingError): except (OperationalError, ProgrammingError):
pass pass
except Exception as e:
logger.exception('Failed to update owners: %s', e)
def update_owners(self): def update_owners(self):
"""Create an 'owner' object for each user and group instance.""" """Create an 'owner' object for each user and group instance."""