Allow reload of plugin registry when config changes (#5662)

* Allow reload of plugin registry when config changes

- Any global settings which control plugin behaviour trigger reload
- Plugin registry hash includes the value of these settings
- Plugin registry hash is now cached

* typo
This commit is contained in:
Oliver 2023-10-05 00:38:40 +11:00 committed by GitHub
parent 4b13f3b0de
commit a6dbe185c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 11 deletions

View File

@ -951,6 +951,16 @@ def update_exchange_rates(setting):
InvenTree.tasks.update_exchange_rates()
def reload_plugin_registry(setting):
"""When a core plugin setting is changed, reload the plugin registry"""
from plugin import registry
logger.info("Reloading plugin registry due to change in setting '%s'", setting.key)
registry.reload_plugins(full_reload=True, force_reload=True, collect=True)
class InvenTreeSetting(BaseInvenTreeSetting):
"""An InvenTreeSetting object is a key:value pair used for storing single values (e.g. one-off settings values).
@ -1704,7 +1714,7 @@ class InvenTreeSetting(BaseInvenTreeSetting):
'description': _('Enable plugins to add URL routes'),
'default': False,
'validator': bool,
'requires_restart': True,
'after_save': reload_plugin_registry,
},
'ENABLE_PLUGINS_NAVIGATION': {
@ -1712,7 +1722,7 @@ class InvenTreeSetting(BaseInvenTreeSetting):
'description': _('Enable plugins to integrate into navigation'),
'default': False,
'validator': bool,
'requires_restart': True,
'after_save': reload_plugin_registry,
},
'ENABLE_PLUGINS_APP': {
@ -1720,7 +1730,7 @@ class InvenTreeSetting(BaseInvenTreeSetting):
'description': _('Enable plugins to add apps'),
'default': False,
'validator': bool,
'requires_restart': True,
'after_save': reload_plugin_registry,
},
'ENABLE_PLUGINS_SCHEDULE': {
@ -1728,7 +1738,7 @@ class InvenTreeSetting(BaseInvenTreeSetting):
'description': _('Enable plugins to run scheduled tasks'),
'default': False,
'validator': bool,
'requires_restart': True,
'after_save': reload_plugin_registry,
},
'ENABLE_PLUGINS_EVENTS': {
@ -1736,7 +1746,7 @@ class InvenTreeSetting(BaseInvenTreeSetting):
'description': _('Enable plugins to respond to internal events'),
'default': False,
'validator': bool,
'requires_restart': True,
'after_save': reload_plugin_registry,
},
"PROJECT_CODES_ENABLED": {

View File

@ -56,7 +56,7 @@ class ScheduleMixin:
@classmethod
def _activate_mixin(cls, registry, plugins, *args, **kwargs):
"""Activate scheudles from plugins with the ScheduleMixin."""
"""Activate schedules from plugins with the ScheduleMixin."""
logger.debug('Activating plugin tasks')
from common.models import InvenTreeSetting

View File

@ -54,6 +54,9 @@ class PluginsRegistry:
self.plugins_inactive: Dict[str, InvenTreePlugin] = {} # List of inactive instances
self.plugins_full: Dict[str, InvenTreePlugin] = {} # List of all plugin instances
# Keep an internal hash of the plugin registry state
self.registry_hash = None
self.plugin_modules: List[InvenTreePlugin] = [] # Holds all discovered plugins
self.mixin_modules: Dict[str, Any] = {} # Holds all discovered mixins
@ -633,17 +636,17 @@ class PluginsRegistry:
from common.models import InvenTreeSetting
plg_hash = self.calculate_plugin_hash()
self.registry_hash = self.calculate_plugin_hash()
try:
old_hash = InvenTreeSetting.get_setting("_PLUGIN_REGISTRY_HASH", "", create=False, cache=False)
except Exception:
old_hash = ""
if old_hash != plg_hash:
if old_hash != self.registry_hash:
try:
logger.debug("Updating plugin registry hash: %s", str(plg_hash))
InvenTreeSetting.set_setting("_PLUGIN_REGISTRY_HASH", plg_hash, change_user=None)
logger.debug("Updating plugin registry hash: %s", str(self.registry_hash))
InvenTreeSetting.set_setting("_PLUGIN_REGISTRY_HASH", self.registry_hash, change_user=None)
except Exception as exc:
logger.exception("Failed to update plugin registry hash: %s", str(exc))
@ -656,6 +659,8 @@ class PluginsRegistry:
from hashlib import md5
from common.models import InvenTreeSetting
data = md5()
# Hash for all loaded plugins
@ -664,6 +669,21 @@ class PluginsRegistry:
data.update(str(plug.version).encode())
data.update(str(plug.is_active()).encode())
# Also hash for all config settings which define plugin behavior
keys = [
'ENABLE_PLUGINS_URL',
'ENABLE_PLUGINS_NAVIGATION',
'ENABLE_PLUGINS_APP',
'ENABLE_PLUGINS_SCHEDULE',
'ENABLE_PLUGINS_EVENTS'
]
for k in keys:
try:
data.update(str(InvenTreeSetting.get_setting(k, False, cache=False, create=False)).encode())
except Exception:
pass
return str(data.hexdigest())
def check_reload(self):
@ -677,13 +697,17 @@ class PluginsRegistry:
logger.debug("Checking plugin registry hash")
# If not already cached, calculate the hash
if not self.registry_hash:
self.registry_hash = self.calculate_plugin_hash()
try:
reg_hash = InvenTreeSetting.get_setting("_PLUGIN_REGISTRY_HASH", "", create=False, cache=False)
except Exception as exc:
logger.exception("Failed to retrieve plugin registry hash: %s", str(exc))
return
if reg_hash and reg_hash != self.calculate_plugin_hash():
if reg_hash and reg_hash != self.registry_hash:
logger.info("Plugin registry hash has changed - reloading")
self.reload_plugins(full_reload=True, force_reload=True, collect=True)