Skip to content

Commit

Permalink
perf: added caching to XBlockSkillsViewSet list endpoint (#208)
Browse files Browse the repository at this point in the history
* perf: added caching to XBlockSkillsViewSet list endpoint

* test: add tests for XBlockSkillsViewSet caching behavior
  • Loading branch information
hamza-56 authored Oct 9, 2024
1 parent a79beea commit f0d956a
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ Change Log
Unreleased

[1.54.0] - 2024-10-02
---------------------
* perf: Added caching to `XBlockSkillsViewSet` list endpoint to improve performance and reduce redundant database queries

[1.53.0] - 2024-08-22
---------------------
* perf: Introduced db_index on the `created` and `is_blacklisted` fields in `XBlockSkillData` model
Expand Down
2 changes: 1 addition & 1 deletion taxonomy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@
# 2. MINOR version when you add functionality in a backwards compatible manner, and
# 3. PATCH version when you make backwards compatible bug fixes.
# More details can be found at https://semver.org/
__version__ = '1.53.0'
__version__ = '1.54.0'

default_app_config = 'taxonomy.apps.TaxonomyConfig' # pylint: disable=invalid-name
15 changes: 15 additions & 0 deletions taxonomy/api/v1/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from collections import OrderedDict

from django_filters.rest_framework import DjangoFilterBackend
from edx_django_utils.cache import TieredCache, get_cache_key
from rest_framework import permissions
from rest_framework.filters import OrderingFilter
from rest_framework.generics import ListAPIView, RetrieveAPIView
Expand All @@ -27,6 +28,7 @@
SkillsQuizSerializer,
XBlocksSkillsSerializer,
)
from taxonomy.constants import CACHE_TIMEOUT_XBLOCK_SKILLS_SECONDS
from taxonomy.models import (
CourseSkills,
Job,
Expand Down Expand Up @@ -320,6 +322,19 @@ def get_queryset(self):
),
).only('id', 'skills', 'usage_key', 'requires_verification', 'auto_processed', 'hash_content')

def list(self, request, *args, **kwargs):
cache_key = get_cache_key(domain='taxonomy', subdomain='xblock_skills', params=request.query_params)

cached_response = TieredCache.get_cached_response(cache_key)
if cached_response.is_found:
return Response(cached_response.value)

response = super().list(request, *args, **kwargs)

TieredCache.set_all_tiers(cache_key, response.data, CACHE_TIMEOUT_XBLOCK_SKILLS_SECONDS)

return response


class JobPathAPIView(TaxonomyAPIViewSetMixin, RetrieveAPIView):
"""
Expand Down
2 changes: 2 additions & 0 deletions taxonomy/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,5 @@ def get_job_posting_query_filter(jobs=None):
JOB_SOURCE_COURSE_SKILL = 'course_skill'
JOB_SOURCE_INDUSTRY = 'industry'
JOB_SKILLS_URL_NAME = 'job-skills'

CACHE_TIMEOUT_XBLOCK_SKILLS_SECONDS = 60 * 60
26 changes: 26 additions & 0 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from random import randint

import mock
from edx_django_utils.cache import TieredCache
from mock import patch
from pytest import mark
from rest_framework import status
Expand Down Expand Up @@ -626,6 +627,31 @@ def test_xblocks_api_with_skill_validation_disabled(self):
assert api_response.status_code == 200
assert api_response.json() == []

def test_list_xblock_skills_cache_hit(self):
cached_data = {'results': [{'id': str(self.xblock_skills[0].id)}]}
with patch.object(
TieredCache,
'get_cached_response',
wraps=TieredCache.get_cached_response
) as mock_get_cached_response:
mock_get_cached_response.return_value = mock.MagicMock(is_found=True, value=cached_data)
response = self.client.get(self.view_url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, cached_data)
mock_get_cached_response.assert_called_once()

def test_list_xblock_skills_caching(self):
with patch.object(TieredCache, 'set_all_tiers') as mock_set_all_tiers, \
patch.object(TieredCache, 'get_cached_response', wraps=TieredCache.get_cached_response) \
as mock_get_cached_response:

mock_get_cached_response.return_value = mock.MagicMock(is_found=False)
response = self.client.get(self.view_url)

self.assertEqual(response.status_code, status.HTTP_200_OK)
mock_get_cached_response.assert_called_once()
mock_set_all_tiers.assert_called_once()


@mark.django_db
class TestJobPathAPIView(TestCase):
Expand Down

0 comments on commit f0d956a

Please sign in to comment.