From 7a5d9ad660e51b7bb0e4a289fbdbd9777e163539 Mon Sep 17 00:00:00 2001 From: Maurits van Rees Date: Fri, 14 Apr 2023 19:04:08 +0200 Subject: [PATCH] Clear the resource viewlet cache when changing the resource registry or activating an add-on. This avoids needing a restart before seeing changes when you run in production mode. Fixes [issue 3505](https://github.com/plone/Products.CMFPlone/issues/3505). --- .../controlpanel/browser/resourceregistry.py | 2 ++ .../CMFPlone/resources/browser/resource.py | 27 +++++++++++++++++-- Products/CMFPlone/resources/configure.zcml | 1 + Products/CMFPlone/resources/eventhandlers.py | 16 +++++++++++ news/3505.bugfix | 4 +++ 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 Products/CMFPlone/resources/eventhandlers.py create mode 100644 news/3505.bugfix diff --git a/Products/CMFPlone/controlpanel/browser/resourceregistry.py b/Products/CMFPlone/controlpanel/browser/resourceregistry.py index e097435ad7..eebcedd0b1 100644 --- a/Products/CMFPlone/controlpanel/browser/resourceregistry.py +++ b/Products/CMFPlone/controlpanel/browser/resourceregistry.py @@ -2,6 +2,7 @@ from plone.base import PloneMessageFactory as _ from plone.base.interfaces import IBundleRegistry from plone.registry.interfaces import IRegistry +from Products.CMFPlone.resources.browser.resource import clear_resource_viewlet_caches from Products.Five.browser import BrowserView from Products.statusmessages.interfaces import IStatusMessage from zope.component import getUtility @@ -149,4 +150,5 @@ def process_form(self): self._switch_cache(False) else: raise ValueError("Invalid form data") + clear_resource_viewlet_caches() self.request.response.redirect(self.request["ACTUAL_URL"]) diff --git a/Products/CMFPlone/resources/browser/resource.py b/Products/CMFPlone/resources/browser/resource.py index c07f71f20a..57654a740a 100644 --- a/Products/CMFPlone/resources/browser/resource.py +++ b/Products/CMFPlone/resources/browser/resource.py @@ -19,7 +19,7 @@ logger = logging.getLogger(__name__) REQUEST_CACHE_KEY = "_WEBRESOURCE_CACHE_" - +SITE_ROOT_CACHE_KEY_PREFIX = "_v_rendered_cache_" GRACEFUL_DEPENDENCY_REWRITE = { "plone-base": "plone", "plone-legacy": "plone", @@ -59,7 +59,7 @@ def _cache_attr_name(self, site): for bundle in e_bundles | d_bundles: hashtool.update(bundle.encode('utf8')) hashtool.update(self._user_local_roles(site).encode("utf8")) - return f"_v_renderend_cache_{hashtool.hexdigest()}" + return f"{SITE_ROOT_CACHE_KEY_PREFIX}{hashtool.hexdigest()}" @property def _rendered_cache(self): @@ -313,3 +313,26 @@ def index(self): rendered = self.renderer["css"].render() self._rendered_cache = rendered return rendered + + +def clear_resource_viewlet_caches(): + """Remove volatile cache of resource viewlets. + + See discussion in https://github.com/plone/Products.CMFPlone/issues/3505 + """ + site = getSite() + + # I don't trust removing keys from a dict when iterating over this dict, + # so gather them in a list first. + to_remove = [ + name for name in site.__dict__ + if name.startswith(SITE_ROOT_CACHE_KEY_PREFIX) + ] + for name in to_remove: + # The attribute is volatile, meaning it may disappear at any time, + # so we catch errors. + try: + delattr(site, name) + except AttributeError: + pass + logger.info("Cleared resource viewlet caches.") diff --git a/Products/CMFPlone/resources/configure.zcml b/Products/CMFPlone/resources/configure.zcml index 0bec1224e4..faf47d627e 100644 --- a/Products/CMFPlone/resources/configure.zcml +++ b/Products/CMFPlone/resources/configure.zcml @@ -3,5 +3,6 @@ i18n_domain="plone.registry"> + diff --git a/Products/CMFPlone/resources/eventhandlers.py b/Products/CMFPlone/resources/eventhandlers.py new file mode 100644 index 0000000000..4bd76de4ba --- /dev/null +++ b/Products/CMFPlone/resources/eventhandlers.py @@ -0,0 +1,16 @@ +from Products.CMFPlone.resources.browser.resource import clear_resource_viewlet_caches +from Products.GenericSetup.interfaces import IProfileImportedEvent +from zope.component import adapter + + +@adapter(IProfileImportedEvent) +def check_registry_update(event): + """Check if a profile import may have updated the configuration registry. + + Main concern for now is: the resource registries may have changed. + This means the resource viewlet caches should be cleared. + See discussion in https://github.com/plone/Products.CMFPlone/issues/3505 + """ + if not (event.full_import or "plone.app.registry" in event.steps): + return + clear_resource_viewlet_caches() diff --git a/news/3505.bugfix b/news/3505.bugfix new file mode 100644 index 0000000000..da1ed7a2c3 --- /dev/null +++ b/news/3505.bugfix @@ -0,0 +1,4 @@ +Clear the resource viewlet cache when changing the resource registry or activating an add-on. +This avoids needing a restart before seeing changes when you run in production mode. +Fixes [issue 3505](https://github.com/plone/Products.CMFPlone/issues/3505). +[maurits]