From a3d9fa177e8ec0035cb92b5c4915e8408b7afde3 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Fri, 30 Sep 2022 09:07:31 +0100 Subject: [PATCH] Replace spotify data cache with new cached properties Also replace the update script with one which will do everything --- etc/crontab | 2 +- .../commands/refresh_spotify_playlists.py | 17 ------- website/spotify/models.py | 17 ++----- .../commands/refresh_model_property_cache.py | 44 +++++++++++++++++++ 4 files changed, 48 insertions(+), 32 deletions(-) delete mode 100644 website/spotify/management/commands/refresh_spotify_playlists.py create mode 100644 website/utils/management/commands/refresh_model_property_cache.py diff --git a/etc/crontab b/etc/crontab index 8807b4a..b1619dd 100644 --- a/etc/crontab +++ b/etc/crontab @@ -1,5 +1,5 @@ @weekly ./manage.py update_index @daily ./manage.py clearsessions @daily ./manage.py update_unsplash_photos -@weekly ./manage.py refresh_spotify_playlists +@weekly ./manage.py refresh_model_property_cache */10 * * * * ./manage.py publish_scheduled_pages diff --git a/website/spotify/management/commands/refresh_spotify_playlists.py b/website/spotify/management/commands/refresh_spotify_playlists.py deleted file mode 100644 index 8e6ca0a..0000000 --- a/website/spotify/management/commands/refresh_spotify_playlists.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.core.cache import cache -from django.core.management.base import BaseCommand - -from website.spotify.models import SpotifyPlaylistPage -from website.utils.queue import enqueue_or_sync - - -def refresh_cache(page_id: int) -> None: - page = SpotifyPlaylistPage.objects.get(id=page_id) - cache.delete(page.playlist_cache_key) - page.playlist_data # Prime cache - - -class Command(BaseCommand): - def handle(self, *args: list, **options: dict) -> None: - for page in SpotifyPlaylistPage.objects.all().defer_streamfields().iterator(): - enqueue_or_sync(refresh_cache, args=[page.id]) diff --git a/website/spotify/models.py b/website/spotify/models.py index 39117d0..cb0dfa1 100644 --- a/website/spotify/models.py +++ b/website/spotify/models.py @@ -1,13 +1,13 @@ from datetime import timedelta from functools import cached_property -from django.core.cache import cache from django.core.exceptions import ValidationError from django.db import models from django.http.request import HttpRequest from wagtail.admin.panels import FieldPanel from website.common.models import BaseContentPage +from website.utils.cache import cached_model_property from . import client @@ -60,20 +60,9 @@ class SpotifyPlaylistPage(BaseContentPage): def subtitle(self) -> str: return self.playlist_data["description"] - @cached_property - def playlist_cache_key(self) -> str: - return f"spotify_playlist_{self.spotify_playlist_id}" - - @cached_property + @cached_model_property def playlist_data(self) -> dict: - playlist_data = cache.get(self.playlist_cache_key) - - if playlist_data is None: - playlist_data = client.get_playlist(self.spotify_playlist_id) - # Cache for 1 week - cache.set(self.playlist_cache_key, playlist_data, 604800) - - return playlist_data + return client.get_playlist(self.spotify_playlist_id) def get_context(self, request: HttpRequest) -> dict: context = super().get_context(request) diff --git a/website/utils/management/commands/refresh_model_property_cache.py b/website/utils/management/commands/refresh_model_property_cache.py new file mode 100644 index 0000000..4ae4443 --- /dev/null +++ b/website/utils/management/commands/refresh_model_property_cache.py @@ -0,0 +1,44 @@ +from django.apps import apps +from django.core.cache import cache +from django.core.management.base import BaseCommand + +from website.utils.cache import get_cache_key, get_cached_model_properties +from website.utils.queue import enqueue_or_sync + + +def refresh_cache( + app_label: str, model_name: str, model_id: int, cached_model_properties: list[str] +) -> None: + Model = apps.get_model(app_label, model_name) + instance = Model.objects.get(id=model_id) + cache.delete_many( + [ + get_cache_key(instance, getattr(instance.__class__, name).real_func) + for name in cached_model_properties + ] + ) + + # Prime caches again + for name in cached_model_properties: + getattr(instance, name) + + +class Command(BaseCommand): + def handle(self, *args: list, **options: dict) -> None: + for Model in apps.get_models(): + cached_model_properties = get_cached_model_properties(Model) + + if not cached_model_properties: + continue + for instance_id in ( + Model.objects.all().values_list("id", flat=True).iterator() + ): + enqueue_or_sync( + refresh_cache, + [ + Model._meta.app_label, + Model._meta.model_name, + instance_id, + cached_model_properties, + ], + )