diff --git a/src/backend/InvenTree/plugin/registry.py b/src/backend/InvenTree/plugin/registry.py index b8e63a6d83..45ea1da45f 100644 --- a/src/backend/InvenTree/plugin/registry.py +++ b/src/backend/InvenTree/plugin/registry.py @@ -88,7 +88,7 @@ class PluginsRegistry: self.plugin_modules: list[InvenTreePlugin] = [] # Holds all discovered plugins 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 @@ -307,6 +307,7 @@ class PluginsRegistry: full_reload: bool = False, force_reload: bool = False, collect: bool = False, + clear_errors: bool = False, _internal: Optional[list] = None, ): """Reload the plugin registry. @@ -317,6 +318,7 @@ class PluginsRegistry: full_reload (bool, optional): Reload everything - including plugin mechanism. Defaults to False. force_reload (bool, optional): Also reload base apps. 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 """ # Do not reload when currently loading @@ -324,7 +326,15 @@ class PluginsRegistry: logger.debug('Skipping reload - plugin registry is currently loading') 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( 'Plugin Registry: Reloading plugins - Force: %s, Full: %s, Collect: %s', force_reload, @@ -343,10 +353,15 @@ class PluginsRegistry: self._load_plugins(full_reload=full_reload, _internal=_internal) self.update_plugin_hash() - - self.loading_lock.release() 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): """Construct a list of directories from where plugins can be loaded.""" # Builtin plugins are *always* loaded diff --git a/src/backend/InvenTree/plugin/serializers.py b/src/backend/InvenTree/plugin/serializers.py index 86ae3edbca..ca35eb3eb9 100644 --- a/src/backend/InvenTree/plugin/serializers.py +++ b/src/backend/InvenTree/plugin/serializers.py @@ -213,6 +213,7 @@ class PluginReloadSerializer(serializers.Serializer): full_reload=self.validated_data.get('full_reload', False), force_reload=self.validated_data.get('force_reload', False), collect=self.validated_data.get('collect_plugins', False), + clear_errors=True, ) diff --git a/src/backend/InvenTree/users/apps.py b/src/backend/InvenTree/users/apps.py index d552fbca69..743b2612ed 100644 --- a/src/backend/InvenTree/users/apps.py +++ b/src/backend/InvenTree/users/apps.py @@ -35,11 +35,15 @@ class UsersConfig(AppConfig): rebuild_all_permissions() except (OperationalError, ProgrammingError): pass + except Exception as e: + logger.exception('Failed to rebuild permissions: %s', e) try: self.update_owners() except (OperationalError, ProgrammingError): pass + except Exception as e: + logger.exception('Failed to update owners: %s', e) def update_owners(self): """Create an 'owner' object for each user and group instance."""