[geany/www.geany.org] 203939: Invalidate relevant cache items once a latest version is saved

Enrico Tröger git-noreply at xxxxx
Sat Oct 31 09:48:37 UTC 2020


Branch:      refs/heads/master
Author:      Enrico Tröger <enrico.troeger at uvena.de>
Committer:   Enrico Tröger <enrico.troeger at uvena.de>
Date:        Sat, 31 Oct 2020 09:48:37 UTC
Commit:      2039399e87b8e8fa766319dda7dbb6d164b93e8d
             https://github.com/geany/www.geany.org/commit/2039399e87b8e8fa766319dda7dbb6d164b93e8d

Log Message:
-----------
Invalidate relevant cache items once a latest version is saved


Modified Paths:
--------------
    geany/decorators.py
    latest_version/context_processors.py
    latest_version/models.py
    static_docs/views.py

Modified: geany/decorators.py
40 lines changed, 24 insertions(+), 16 deletions(-)
===================================================================
@@ -23,9 +23,12 @@
 CACHE_TIMEOUT_24HOURS = 3600 * 24
 CACHE_TIMEOUT_1HOUR = 3600
 
+CACHE_KEY_LATEST_VERSION_LATEST_VERSION = 'latest_version.latest_version'
+CACHE_KEY_STATIC_DOCS_RELEASE_NOTES = 'static_docs.release_notes'
+
 
 # ----------------------------------------------------------------------
-def cache_function(timeout=900, ignore_arguments=False):
+def cache_function(timeout=900, ignore_arguments=False, key=None):
     """
         Cache the result of a function call for the specified number of seconds,
         using Django's caching mechanism.
@@ -35,6 +38,9 @@ def cache_function(timeout=900, ignore_arguments=False):
         myFunction(x = 1, y = 2), myFunction(y = 2, x = 1), and myFunction(1,2)
         will each be cached separately.
 
+        If the keyword argument `key` is provided, automatic cache key generation is skipped
+        and the passed key is used instead (expected as string).
+
         Usage:
 
         @cache(600)
@@ -44,23 +50,25 @@ def myExpensiveMethod(parm1, parm2, parm3):
     """
     def do_cache(function):
         def wrapped(*args, **kwargs):
-            key = '%s.%s' % ((function.__module__, function.__name__))
-            if args and not ignore_arguments:
-                cache_args = args
-                # don't include 'self' in arguments
-                arguments = inspect.getfullargspec(function)
-                if arguments and arguments.args[0] == 'self':
-                    cache_args = args[1:]
-                if cache_args:
-                    cache_args_repr = repr(cache_args).encode('utf-8')
-                    key = '%s.args%s' % (key, hexlify(cache_args_repr))
-            if kwargs and not ignore_arguments:
-                kwargs_repr = repr(kwargs).encode('utf-8')
-                key = '%s.kwargs%s' % (key, hexlify(kwargs_repr))
-            result = _djcache.get(key)
+            cache_key = key
+            if cache_key is None:
+                cache_key = '%s.%s' % ((function.__module__, function.__name__))
+                if args and not ignore_arguments:
+                    cache_args = args
+                    # don't include 'self' in arguments
+                    arguments = inspect.getfullargspec(function)
+                    if arguments and arguments.args[0] == 'self':
+                        cache_args = args[1:]
+                    if cache_args:
+                        cache_args_repr = repr(cache_args).encode('utf-8')
+                        cache_key = '%s.args%s' % (cache_key, hexlify(cache_args_repr))
+                if kwargs and not ignore_arguments:
+                    kwargs_repr = repr(kwargs).encode('utf-8')
+                    cache_key = '%s.kwargs%s' % (cache_key, hexlify(kwargs_repr))
+            result = _djcache.get(cache_key)
             if result is None:
                 result = function(*args, **kwargs)
-                _djcache.set(key, result, timeout)
+                _djcache.set(cache_key, result, timeout)
             return result
         return wrapped
     return do_cache


Modified: latest_version/context_processors.py
8 lines changed, 6 insertions(+), 2 deletions(-)
===================================================================
@@ -14,13 +14,17 @@
 
 from mezzanine.conf import settings
 
-from geany.decorators import cache_function, CACHE_TIMEOUT_1HOUR
+from geany.decorators import (
+    cache_function,
+    CACHE_KEY_LATEST_VERSION_LATEST_VERSION,
+    CACHE_TIMEOUT_1HOUR,
+)
 from latest_version.models import LatestVersion
 from latest_version.releases import ReleaseVersionsProvider
 
 
 # ----------------------------------------------------------------------
- at cache_function(CACHE_TIMEOUT_1HOUR, ignore_arguments=True)
+ at cache_function(CACHE_TIMEOUT_1HOUR, key=CACHE_KEY_LATEST_VERSION_LATEST_VERSION)
 def latest_version(request):
     latest_versions = LatestVersion.objects.all()
     latest_versions_by_name = {


Modified: latest_version/models.py
13 lines changed, 13 insertions(+), 0 deletions(-)
===================================================================
@@ -12,8 +12,14 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+from django.core.cache import cache
 from django.db import models
 
+from geany.decorators import (
+    CACHE_KEY_LATEST_VERSION_LATEST_VERSION,
+    CACHE_KEY_STATIC_DOCS_RELEASE_NOTES,
+)
+
 
 class LatestVersion(models.Model):
 
@@ -33,6 +39,13 @@ class Meta:
     def delete(self, using=None, keep_parents=False):
         """Never delete anything"""
 
+    # ----------------------------------------------------------------------
+    def save(self, *args, **kwargs):  # pylint: disable=signature-differs
+        super().save(*args, **kwargs)
+        # invalidate related cached data
+        cache.delete_many(
+            [CACHE_KEY_LATEST_VERSION_LATEST_VERSION, CACHE_KEY_STATIC_DOCS_RELEASE_NOTES])
+
     # ----------------------------------------------------------------------
     def __str__(self):
         return '{} {}'.format(self.name, self.version)


Modified: static_docs/views.py
9 lines changed, 7 insertions(+), 2 deletions(-)
===================================================================
@@ -24,7 +24,12 @@
 from django.views.generic.base import TemplateView
 from mezzanine_pagedown.filters import plain as markdown_plain
 
-from geany.decorators import cache_function, CACHE_TIMEOUT_1HOUR, CACHE_TIMEOUT_24HOURS
+from geany.decorators import (
+    cache_function,
+    CACHE_KEY_STATIC_DOCS_RELEASE_NOTES,
+    CACHE_TIMEOUT_1HOUR,
+    CACHE_TIMEOUT_24HOURS,
+)
 from static_docs.github_client import GitHubApiClient
 
 
@@ -86,7 +91,7 @@ def get_context_data(self, **kwargs):
         return context
 
     # ----------------------------------------------------------------------
-    @cache_function(CACHE_TIMEOUT_24HOURS)
+    @cache_function(CACHE_TIMEOUT_24HOURS, key=CACHE_KEY_STATIC_DOCS_RELEASE_NOTES)
     def _get_release_notes(self):
         self._fetch_file_via_github_api('NEWS')
         return self._parse_news_file()



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list