Skip to content

Commit

Permalink
refactor: create cache_utils.py, move stuff there
Browse files Browse the repository at this point in the history
This will eventually support the creation of a `content_metadata`
module, and we'll yank stuff out of the `subsidy_access_policy` module
into this new module.
  • Loading branch information
iloveagent57 committed Oct 26, 2023
1 parent 9ad845b commit cc341c0
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 42 deletions.
2 changes: 1 addition & 1 deletion enterprise_access/apps/content_assignments/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ def _get_content_title(assignment_configuration, content_key):
assignment_configuration.enterprise_customer_uuid,
content_key,
)
return content_metadata['title']
return content_metadata.get('title')


def _create_new_assignments(assignment_configuration, learner_emails, content_key, content_quantity):
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
from edx_django_utils.cache import TieredCache
from requests.exceptions import HTTPError

from enterprise_access.cache_utils import versioned_cache_key

from ..api_client.enterprise_catalog_client import EnterpriseCatalogApiClient
from .utils import get_versioned_subsidy_client, versioned_cache_key
from .utils import get_versioned_subsidy_client

logger = logging.getLogger(__name__)

Expand All @@ -28,6 +30,7 @@ def get_and_cache_content_metadata(enterprise_customer_uuid, content_key, timeou
cache_key = versioned_cache_key('get_subsidy_content_metadata', enterprise_customer_uuid, content_key)
cached_response = TieredCache.get_cached_response(cache_key)
if cached_response.is_found:
logger.info(f'cache hit for customer {enterprise_customer_uuid} and content {content_key}')
return cached_response.value

client = get_versioned_subsidy_client()
Expand Down Expand Up @@ -57,6 +60,7 @@ def get_and_cache_catalog_contains_content(enterprise_catalog_uuid, content_key,
cache_key = versioned_cache_key('contains_content_key', enterprise_catalog_uuid, content_key)
cached_response = TieredCache.get_cached_response(cache_key)
if cached_response.is_found:
logger.info(f'cache hit for catalog {enterprise_catalog_uuid} and content {content_key}')
return cached_response.value

try:
Expand Down
16 changes: 6 additions & 10 deletions enterprise_access/apps/subsidy_access_policy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from enterprise_access.apps.api_client.lms_client import LmsApiClient
from enterprise_access.apps.content_assignments import api as assignments_api
from enterprise_access.apps.content_assignments.constants import LearnerContentAssignmentStateChoices
from enterprise_access.cache_utils import request_cache, versioned_cache_key
from enterprise_access.utils import is_none, is_not_none

from ..content_assignments.models import AssignmentConfiguration
Expand Down Expand Up @@ -44,15 +45,10 @@
SubsidyAPIHTTPError
)
from .subsidy_api import get_and_cache_transactions_for_learner
from .utils import (
ProxyAwareHistoricalRecords,
create_idempotency_key_for_transaction,
get_versioned_subsidy_client,
request_cache,
versioned_cache_key
)
from .utils import ProxyAwareHistoricalRecords, create_idempotency_key_for_transaction, get_versioned_subsidy_client

POLICY_LOCK_RESOURCE_NAME = "subsidy_access_policy"
REQUEST_CACHE_NAMESPACE = 'subsidy_access_policy'
POLICY_LOCK_RESOURCE_NAME = 'subsidy_access_policy'
logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -296,7 +292,7 @@ def subsidy_record(self):
self.enterprise_customer_uuid,
self.subsidy_uuid,
)
cached_response = request_cache().get_cached_response(cache_key)
cached_response = request_cache(namespace=REQUEST_CACHE_NAMESPACE).get_cached_response(cache_key)
if cached_response.is_found:
logger.info(
'subsidy_record cache hit '
Expand All @@ -311,7 +307,7 @@ def subsidy_record(self):
logger.warning('SubsidyAccessPolicy.subsidy_record() raised HTTPError: %s', exc)
result = {}

request_cache().set(cache_key, result)
request_cache(namespace=REQUEST_CACHE_NAMESPACE).set(cache_key, result)

logger.info(
'subsidy_record cache miss '
Expand Down
11 changes: 8 additions & 3 deletions enterprise_access/apps/subsidy_access_policy/subsidy_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@

import requests

from enterprise_access.cache_utils import request_cache, versioned_cache_key

from .exceptions import SubsidyAPIHTTPError
from .utils import get_versioned_subsidy_client, request_cache, versioned_cache_key
from .utils import get_versioned_subsidy_client

logger = logging.getLogger(__name__)

REQUEST_CACHE_NAMESPACE = 'subsidy_access_policy'


class TransactionPolicyMismatchError(Exception):
"""
Expand All @@ -32,8 +36,9 @@ def get_and_cache_transactions_for_learner(subsidy_uuid, lms_user_id):
include transactions from multiple access policies.
"""
cache_key = learner_transaction_cache_key(subsidy_uuid, lms_user_id)
cached_response = request_cache().get_cached_response(cache_key)
cached_response = request_cache(namespace=REQUEST_CACHE_NAMESPACE).get_cached_response(cache_key)
if cached_response.is_found:
logger.info(f'cache hit for subsidy {subsidy_uuid} and user {lms_user_id}')
return cached_response.value

client = get_versioned_subsidy_client()
Expand Down Expand Up @@ -65,7 +70,7 @@ def get_and_cache_transactions_for_learner(subsidy_uuid, lms_user_id):
lms_user_id,
len(result['transactions']),
)
request_cache().set(cache_key, result)
request_cache(namespace=REQUEST_CACHE_NAMESPACE).set(cache_key, result)
return result


Expand Down
27 changes: 0 additions & 27 deletions enterprise_access/apps/subsidy_access_policy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,9 @@

from django.apps import apps
from django.conf import settings
from edx_django_utils.cache import RequestCache
from edx_enterprise_subsidy_client import get_enterprise_subsidy_api_client
from simple_history.models import HistoricalRecords, registered_models

from enterprise_access import __version__ as code_version

CACHE_KEY_SEP = ':'
CACHE_NAMESPACE = 'subsidy_access_policy'

LEDGERED_SUBSIDY_IDEMPOTENCY_KEY_PREFIX = 'ledger-for-subsidy'
TRANSACTION_METADATA_KEYS = {
'lms_user_id',
Expand All @@ -34,27 +28,6 @@ def get_versioned_subsidy_client():
return get_enterprise_subsidy_api_client(**kwargs)


def versioned_cache_key(*args):
"""
Utility to produce a versioned cache key, which includes
an optional settings variable and the current code version,
so that we can perform key-based cache invalidation.
"""
components = [str(arg) for arg in args]
components.append(code_version)
if stamp_from_settings := getattr(settings, 'CACHE_KEY_VERSION_STAMP', None):
components.append(stamp_from_settings)
decoded_cache_key = CACHE_KEY_SEP.join(components)
return hashlib.sha512(decoded_cache_key.encode()).hexdigest()


def request_cache():
"""
Helper that returns a namespaced RequestCache instance.
"""
return RequestCache(namespace=CACHE_NAMESPACE)


def create_idempotency_key_for_transaction(subsidy_uuid, **metadata):
"""
Create a key that allows a transaction to be created idempotently.
Expand Down
33 changes: 33 additions & 0 deletions enterprise_access/cache_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
Utils for interacting with cache interfaces.
"""
import hashlib

from django.conf import settings
from edx_django_utils.cache import RequestCache

from enterprise_access import __version__ as code_version

CACHE_KEY_SEP = ':'
DEFAULT_NAMESPACE = 'enterprise-access-default'


def versioned_cache_key(*args):
"""
Utility to produce a versioned cache key, which includes
an optional settings variable and the current code version,
so that we can perform key-based cache invalidation.
"""
components = [str(arg) for arg in args]
components.append(code_version)
if stamp_from_settings := getattr(settings, 'CACHE_KEY_VERSION_STAMP', None):
components.append(stamp_from_settings)
decoded_cache_key = CACHE_KEY_SEP.join(components)
return hashlib.sha512(decoded_cache_key.encode()).hexdigest()


def request_cache(namespace=DEFAULT_NAMESPACE):
"""
Helper that returns a namespaced RequestCache instance.
"""
return RequestCache(namespace=namespace)

0 comments on commit cc341c0

Please sign in to comment.