[FEAT]: Add mem caching to the API to create and retrieve IntegritySignature (#27922)
With this change, whenever a IntegritySignature is created or retrieved, the result will be cached into mem cache for future use. This will save round trip to database significantly for honor code check
This commit is contained in:
@@ -5,9 +5,11 @@ Agreements API
|
||||
import logging
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from opaque_keys.edx.keys import CourseKey
|
||||
|
||||
from openedx.core.djangoapps.agreements.cache import get_integrity_signature_cache_key
|
||||
from openedx.core.djangoapps.agreements.models import IntegritySignature
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -33,6 +35,9 @@ def create_integrity_signature(username, course_id):
|
||||
'Integrity signature already exists for user_id={user_id} and '
|
||||
'course_id={course_id}'.format(user_id=user.id, course_id=course_id)
|
||||
)
|
||||
cache_key = get_integrity_signature_cache_key(username, course_id)
|
||||
# Write into the cache for future retrieval
|
||||
cache.set(cache_key, signature)
|
||||
return signature
|
||||
|
||||
|
||||
@@ -48,10 +53,17 @@ def get_integrity_signature(username, course_id):
|
||||
* An IntegritySignature object, or None if one does not exist for the
|
||||
user + course combination.
|
||||
"""
|
||||
cache_key = get_integrity_signature_cache_key(username, course_id)
|
||||
cached_integrity_signature = cache.get(cache_key)
|
||||
if cached_integrity_signature:
|
||||
return cached_integrity_signature
|
||||
|
||||
user = User.objects.get(username=username)
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
try:
|
||||
return IntegritySignature.objects.get(user=user, course_key=course_key)
|
||||
signature = IntegritySignature.objects.get(user=user, course_key=course_key)
|
||||
cache.set(cache_key, signature)
|
||||
return signature
|
||||
except ObjectDoesNotExist:
|
||||
return None
|
||||
|
||||
@@ -66,5 +78,12 @@ def get_integrity_signatures_for_course(course_id):
|
||||
Returns:
|
||||
* QuerySet of IntegritySignature objects (can be empty).
|
||||
"""
|
||||
|
||||
course_key = CourseKey.from_string(course_id)
|
||||
return IntegritySignature.objects.filter(course_key=course_key)
|
||||
course_integrity_signature = IntegritySignature.objects.filter(
|
||||
course_key=course_key
|
||||
).select_related('user')
|
||||
for signature in course_integrity_signature:
|
||||
cache_key = get_integrity_signature_cache_key(signature.user.username, course_id)
|
||||
cache.set(cache_key, signature)
|
||||
return course_integrity_signature
|
||||
|
||||
13
openedx/core/djangoapps/agreements/cache.py
Normal file
13
openedx/core/djangoapps/agreements/cache.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# lint-amnesty, pylint: disable=missing-module-docstring
|
||||
# Template used to create cache keys for Integrity Signatures
|
||||
INTEGRITY_SIGNATURE_CACHE_KEY_TPL = 'integrity-signature-{course_id}-{username}'
|
||||
|
||||
|
||||
def get_integrity_signature_cache_key(username, course_id):
|
||||
"""
|
||||
Util function to help form the cache key for integrity signature
|
||||
"""
|
||||
return INTEGRITY_SIGNATURE_CACHE_KEY_TPL.format(
|
||||
username=username,
|
||||
course_id=course_id,
|
||||
)
|
||||
@@ -3,13 +3,14 @@ Tests for the Agreements API
|
||||
"""
|
||||
import logging
|
||||
|
||||
from django.core.cache import cache
|
||||
from testfixtures import LogCapture
|
||||
|
||||
from common.djangoapps.student.tests.factories import UserFactory
|
||||
from openedx.core.djangoapps.agreements.api import (
|
||||
create_integrity_signature,
|
||||
get_integrity_signature,
|
||||
get_integrity_signatures_for_course,
|
||||
get_integrity_signatures_for_course
|
||||
)
|
||||
from openedx.core.djangolib.testing.utils import skip_unless_lms
|
||||
from xmodule.modulestore.tests.django_utils import SharedModuleStoreTestCase
|
||||
@@ -62,15 +63,17 @@ class TestIntegritySignatureApi(SharedModuleStoreTestCase):
|
||||
Test to get an integrity signature
|
||||
"""
|
||||
create_integrity_signature(self.user.username, self.course_id)
|
||||
signature = get_integrity_signature(self.user.username, self.course_id)
|
||||
self._assert_integrity_signature(signature)
|
||||
with self.assertNumQueries(0):
|
||||
signature = get_integrity_signature(self.user.username, self.course_id)
|
||||
self._assert_integrity_signature(signature)
|
||||
|
||||
def test_get_nonexistent_integrity_signature(self):
|
||||
"""
|
||||
Test that None is returned if an integrity signature does not exist
|
||||
"""
|
||||
signature = get_integrity_signature(self.user.username, self.course_id)
|
||||
self.assertIsNone(signature)
|
||||
with self.assertNumQueries(2):
|
||||
signature = get_integrity_signature(self.user.username, self.course_id)
|
||||
self.assertIsNone(signature)
|
||||
|
||||
def test_get_integrity_signatures_for_course(self):
|
||||
"""
|
||||
@@ -98,3 +101,21 @@ class TestIntegritySignatureApi(SharedModuleStoreTestCase):
|
||||
"""
|
||||
self.assertEqual(signature.user, self.user)
|
||||
self.assertEqual(signature.course_key, self.course.id)
|
||||
|
||||
def test_get_integrity_signatures_for_course_cached(self):
|
||||
"""
|
||||
Test to ensure the integrity_signatures retrieved by course is also set into cache
|
||||
"""
|
||||
create_integrity_signature(self.user.username, self.course_id)
|
||||
second_user = UserFactory()
|
||||
create_integrity_signature(second_user.username, self.course_id)
|
||||
cache.clear()
|
||||
with self.assertNumQueries(1):
|
||||
get_integrity_signatures_for_course(self.course_id)
|
||||
|
||||
with self.assertNumQueries(0):
|
||||
signature = get_integrity_signature(self.user.username, self.course_id)
|
||||
self._assert_integrity_signature(signature)
|
||||
|
||||
with self.assertNumQueries(0):
|
||||
get_integrity_signature(second_user.username, self.course_id)
|
||||
|
||||
Reference in New Issue
Block a user