def _update_cache(cls, course_key, visible_blocks): """ Adds a specific set of visible blocks to the request cache. This assumes that prefetch has already been called. """ get_cache(cls.CACHE_NAMESPACE)[cls._cache_key(course_key)].update( {visible_block.hashed: visible_block for visible_block in visible_blocks} )
def __enter__(self): connection = transaction.get_connection(self.using) cache = request_cache.get_cache(OUTER_ATOMIC_CACHE_NAME) # By default it is enabled. enable = True # If name is set it is only enabled if requested by calling enable_named_outer_atomic(). if self.name: enable = cache.get(self.name, False) if enable: # TestCase setup nests tests in two atomics - one for the test class and one for the individual test. # The outermost atomic starts a transaction - so does not have a savepoint. # The inner atomic starts a savepoint around the test. # So, for tests only, there should be exactly one savepoint_id and two atomic_for_testcase_calls. # atomic_for_testcase_calls below is added in a monkey-patch for tests only. if self.ALLOW_NESTED and (self.atomic_for_testcase_calls - len(connection.savepoint_ids)) < 1: raise transaction.TransactionManagementError('Cannot be inside an atomic block.') # Otherwise, this shouldn't be nested in any atomic block. if not self.ALLOW_NESTED and connection.in_atomic_block: raise transaction.TransactionManagementError('Cannot be inside an atomic block.') # This will set the transaction isolation level to READ COMMITTED for the next transaction. if self.read_committed is True: if connection.vendor == 'mysql': cursor = connection.cursor() cursor.execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED") super(OuterAtomic, self).__enter__()
def bulk_cache_cohorts(course_key, users): """ Pre-fetches and caches the cohort assignments for the given users, for later fast retrieval by get_cohort. """ # before populating the cache with another bulk set of data, # remove previously cached entries to keep memory usage low. request_cache.clear_cache(COHORT_CACHE_NAMESPACE) cache = request_cache.get_cache(COHORT_CACHE_NAMESPACE) if is_course_cohorted(course_key): cohorts_by_user = { membership.user: membership for membership in CohortMembership.objects.filter( user__in=users, course_id=course_key).select_related('user') } for user, membership in cohorts_by_user.iteritems(): cache[_cohort_cache_key(user.id, course_key)] = membership.course_user_group uncohorted_users = filter(lambda u: u not in cohorts_by_user, users) else: uncohorted_users = users for user in uncohorted_users: cache[_cohort_cache_key(user.id, course_key)] = None
def process_response(self, __, response): """ If request is from mobile native app, then add version related info to response headers. Returns: Http response: with additional headers; 1. EDX-APP-LATEST-VERSION; if user app version < latest available version 2. EDX-APP-VERSION-LAST-SUPPORTED-DATE; if user app version < min supported version and timestamp < expiry of that version """ request_cache_dict = request_cache.get_cache(self.REQUEST_CACHE_NAME) if request_cache_dict: last_supported_date = request_cache_dict[ self.LAST_SUPPORTED_DATE_HEADER] if last_supported_date != self.NO_LAST_SUPPORTED_DATE: response[ self. LAST_SUPPORTED_DATE_HEADER] = last_supported_date.isoformat( ) latest_version = request_cache_dict[self.LATEST_VERSION_HEADER] user_app_version = request_cache_dict[self.USER_APP_VERSION] if (latest_version != self.NO_LATEST_VERSION and parsed_version(user_app_version) < parsed_version(latest_version)): response[self.LATEST_VERSION_HEADER] = latest_version return response
def get_group_info_for_cohort(cohort, use_cached=False): """ Get the ids of the group and partition to which this cohort has been linked as a tuple of (int, int). If the cohort has not been linked to any group/partition, both values in the tuple will be None. The partition group info is cached for the duration of a request. Pass use_cached=True to use the cached value instead of fetching from the database. """ cache = request_cache.get_cache(u"cohorts.get_group_info_for_cohort") cache_key = unicode(cohort.id) if use_cached and cache_key in cache: return cache[cache_key] cache.pop(cache_key, None) try: partition_group = CourseUserGroupPartitionGroup.objects.get( course_user_group=cohort) return cache.setdefault( cache_key, (partition_group.group_id, partition_group.partition_id)) except CourseUserGroupPartitionGroup.DoesNotExist: pass return cache.setdefault(cache_key, (None, None))
def get_group_info_for_cohort(cohort, use_cached=False): """ Get the ids of the group and partition to which this cohort has been linked as a tuple of (int, int). If the cohort has not been linked to any group/partition, both values in the tuple will be None. The partition group info is cached for the duration of a request. Pass use_cached=True to use the cached value instead of fetching from the database. """ cache = request_cache.get_cache(u"cohorts.get_group_info_for_cohort") cache_key = unicode(cohort.id) if use_cached and cache_key in cache: return cache[cache_key] cache.pop(cache_key, None) try: partition_group = CourseUserGroupPartitionGroup.objects.get(course_user_group=cohort) return cache.setdefault(cache_key, (partition_group.group_id, partition_group.partition_id)) except CourseUserGroupPartitionGroup.DoesNotExist: pass return cache.setdefault(cache_key, (None, None))
def get_template_request_context(request=None): """ Returns the template processing context to use for the current request, or returns None if there is not a current request. """ if request is None: request = get_current_request() if request is None: return None request_cache_dict = request_cache.get_cache('edxmako') cache_key = "request_context" if cache_key in request_cache_dict: return request_cache_dict[cache_key] context = RequestContext(request) context['is_secure'] = request.is_secure() context['site'] = safe_get_host(request) # This used to happen when a RequestContext object was initialized but was # moved to a different part of the logic when template engines were introduced. # Since we are not using template engines we do this here. # https://github.com/django/django/commit/37505b6397058bcc3460f23d48a7de9641cd6ef0 for processor in get_template_context_processors(): context.update(processor(request)) request_cache_dict[cache_key] = context return context
def get_course_content_milestones(course_id, content_id, relationship, user_id=None): """ Client API operation adapter/wrapper Uses the request cache to store all of a user's milestones """ if not settings.FEATURES.get('MILESTONES_APP'): return [] if user_id is None: return milestones_api.get_course_content_milestones( course_id, content_id, relationship) request_cache_dict = request_cache.get_cache(REQUEST_CACHE_NAME) if user_id not in request_cache_dict: request_cache_dict[user_id] = {} if relationship not in request_cache_dict[user_id]: request_cache_dict[user_id][ relationship] = milestones_api.get_course_content_milestones( course_key=course_id, relationship=relationship, user={"id": user_id}) return [ m for m in request_cache_dict[user_id][relationship] if m['content_id'] == unicode(content_id) ]
def get_template_request_context(request=None): """ Returns the template processing context to use for the current request, or returns None if there is not a current request. """ if request is None: request = get_current_request() if request is None: return None request_cache_dict = request_cache.get_cache('edxmako') cache_key = "request_context" if cache_key in request_cache_dict: return request_cache_dict[cache_key] context = RequestContext(request) context['is_secure'] = request.is_secure() context['site'] = safe_get_host(request) request_cache_dict[cache_key] = context return context
def user_timezone_locale_prefs(request): """ Checks if request has an authenticated user. If so, sends set (or none if unset) time_zone and language prefs. This interacts with the DateUtils to either display preferred or attempt to determine system/browser set time_zones and languages """ cached_value = request_cache.get_cache(CACHE_NAME) if not cached_value: user_prefs = { 'user_timezone': None, 'user_language': None, } if hasattr(request, 'user') and request.user.is_authenticated(): try: user_preferences = get_user_preferences(request.user) except (UserNotFound, UserAPIInternalError): cached_value.update(user_prefs) else: user_prefs = { key: user_preferences.get(pref_name, None) for key, pref_name in RETRIEVABLE_PREFERENCES.iteritems() } cached_value.update(user_prefs) return cached_value
def create_new_event_transaction_id(): """ Sets the event transaction id to a newly- generated UUID. """ new_id = uuid4() get_cache('event_transaction')['id'] = new_id return new_id
def set_event_transaction_id(new_id): """ Sets the event transaction id to a UUID object generated from new_id. new_id must be a parsable string version of a UUID. """ get_cache('event_transaction')['id'] = UUID(new_id)
def prefetch(cls, course_id, users): """ Prefetches grades for the given users for the given course. """ get_cache(cls.CACHE_NAMESPACE)[cls._cache_key(course_id)] = { grade.user_id: grade for grade in cls.objects.filter(user_id__in=[user.id for user in users], course_id=course_id) }
def _initialize_cache(cls, course_key): """ Prefetches visible blocks for the given course and stores in the cache. Returns a dictionary mapping hashes of these block records to the block record objects. """ prefetched = {record.hashed: record for record in cls.objects.filter(course_id=course_key)} get_cache(cls.CACHE_NAMESPACE)[cls._cache_key(course_key)] = prefetched return prefetched
def prefetch(cls, users): roles_by_user = defaultdict(set) get_cache(cls.CACHE_NAMESPACE)[cls.CACHE_KEY] = roles_by_user for role in CourseAccessRole.objects.filter(user__in=users).select_related('user'): roles_by_user[role.user.id].add(role) users_without_roles = filter(lambda u: u.id not in roles_by_user, users) for user in users_without_roles: roles_by_user[user.id] = set()
def get_override(cls, user_id, usage_key): prefetch_values = get_cache(cls._CACHE_NAMESPACE).get((user_id, str(usage_key.course_key)), None) if prefetch_values is not None: return prefetch_values.get(usage_key) try: return cls.objects.get( grade__user_id=user_id, grade__course_id=usage_key.course_key, grade__usage_key=usage_key, ) except PersistentSubsectionGradeOverride.DoesNotExist: pass
def prefetch(cls, users): roles_by_user = defaultdict(set) get_cache(cls.CACHE_NAMESPACE)[cls.CACHE_KEY] = roles_by_user for role in CourseAccessRole.objects.filter( user__in=users).select_related('user__id'): roles_by_user[role.user.id].add(role) users_without_roles = filter(lambda u: u.id not in roles_by_user, users) for user in users_without_roles: roles_by_user[user.id] = set()
def get_override(cls, user_id, usage_key): prefetch_values = get_cache(cls._CACHE_NAMESPACE).get( (user_id, str(usage_key.course_key)), None) if prefetch_values is not None: return prefetch_values.get(usage_key) try: return cls.objects.get( grade__user_id=user_id, grade__course_id=usage_key.course_key, grade__usage_key=usage_key, ) except PersistentSubsectionGradeOverride.DoesNotExist: pass
def bulk_read(cls, course_key): """ Reads and returns all visible block records for the given course from the cache. The cache is initialize with the visible blocks for this course if no entry currently exists.has no entry for this course, the cache is updated. Arguments: course_key: The course identifier for the desired records """ prefetched = get_cache(cls.CACHE_NAMESPACE).get(cls._cache_key(course_key)) if not prefetched: prefetched = cls._initialize_cache(course_key) return prefetched
def cached_get_or_create(cls, blocks): prefetched = get_cache(cls._CACHE_NAMESPACE).get(cls._cache_key(blocks.course_key)) if prefetched is not None: model = prefetched.get(blocks.hash_value) if not model: model = cls.objects.create( hashed=blocks.hash_value, blocks_json=blocks.json_value, course_id=blocks.course_key, ) cls._update_cache(blocks.course_key, [model]) else: model, _ = cls.objects.get_or_create( hashed=blocks.hash_value, defaults={u'blocks_json': blocks.json_value, u'course_id': blocks.course_key}, ) return model
def get_current_ccx(course_key): """ Return the ccx that is active for this course. course_key is expected to be an instance of an opaque CourseKey, a ValueError is raised if this expectation is not met. """ if not isinstance(course_key, CourseKey): raise ValueError("get_current_ccx requires a CourseKey instance") if not isinstance(course_key, CCXLocator): return None ccx_cache = request_cache.get_cache('ccx') if course_key not in ccx_cache: ccx_cache[course_key] = CustomCourseForEdX.objects.get(pk=course_key.ccx) return ccx_cache[course_key]
def _get_overrides_for_ccx(ccx): """ Returns a dictionary mapping field name to overriden value for any overrides set on this block for this CCX. """ overrides_cache = request_cache.get_cache('ccx-overrides') if ccx not in overrides_cache: overrides = {} query = CcxFieldOverride.objects.filter(ccx=ccx, ) for override in query: block_overrides = overrides.setdefault(override.location, {}) block_overrides[override.field] = json.loads(override.value) overrides_cache[ccx] = overrides return overrides_cache[ccx]
def prefetch(cls, course_id, users): """ Prefetches the value of the course tags for the specified users for the specified course_id. Args: users: iterator of User objects course_id: course identifier (CourseKey) Returns: course_tags: a dict of dicts, where the primary key is the user's id and the secondary key is the course tag's key """ course_tags = defaultdict(dict) for tag in UserCourseTag.objects.filter(user__in=users, course_id=course_id).select_related('user'): course_tags[tag.user.id][tag.key] = tag.value get_cache(cls.CACHE_NAMESPACE)[cls._cache_key(course_id)] = course_tags
def prefetch(cls, course_id, users): """ Prefetches the value of the course tags for the specified users for the specified course_id. Args: users: iterator of User objects course_id: course identifier (CourseKey) Returns: course_tags: a dict of dicts, where the primary key is the user's id and the secondary key is the course tag's key """ course_tags = defaultdict(dict) for tag in UserCourseTag.objects.filter(user__in=users, course_id=course_id).select_related('user__id'): course_tags[tag.user.id][tag.key] = tag.value get_cache(cls.CACHE_NAMESPACE)[cls._cache_key(course_id)] = course_tags
def _get_version_info(self, request): """ Gets and Sets version related info in mem cache and request cache; and returns a dict of it. It sets request cache data for last_supported_date and latest_version with memcached values if exists against user app properties else computes the values for specific platform and sets it in both memcache (for next server interaction from same app version/platform) and request cache Returns: dict: Containing app version info """ user_agent = request.META.get('HTTP_USER_AGENT') if user_agent: platform = self._get_platform(request, user_agent) if platform: request_cache_dict = request_cache.get_cache( self.REQUEST_CACHE_NAME) request_cache_dict[self.USER_APP_VERSION] = platform.version last_supported_date_cache_key = self._get_cache_key_name( self.LAST_SUPPORTED_DATE_HEADER, platform.version) latest_version_cache_key = self._get_cache_key_name( self.LATEST_VERSION_HEADER, platform.NAME) cached_data = cache.get_many( [last_supported_date_cache_key, latest_version_cache_key]) last_supported_date = cached_data.get( last_supported_date_cache_key) if not last_supported_date: last_supported_date = self._get_last_supported_date( platform.NAME, platform.version) cache.set(last_supported_date_cache_key, last_supported_date, self.CACHE_TIMEOUT) request_cache_dict[ self.LAST_SUPPORTED_DATE_HEADER] = last_supported_date latest_version = cached_data.get(latest_version_cache_key) if not latest_version: latest_version = self._get_latest_version(platform.NAME) cache.set(latest_version_cache_key, latest_version, self.CACHE_TIMEOUT) request_cache_dict[self.LATEST_VERSION_HEADER] = latest_version return request_cache_dict
def enable_named_outer_atomic(*names): """ Enable outer_atomics with names. Can be used either as a decorator or a context manager. See docstring of outer_atomic for details. Arguments: names (variable-lenght argument list): Names of outer_atomics. """ if len(names) == 0: raise ValueError("At least one name must be specified.") cache = request_cache.get_cache(OUTER_ATOMIC_CACHE_NAME) for name in names: cache[name] = True yield for name in names: del cache[name]
def _get_overrides_for_ccx(ccx): """ Returns a dictionary mapping field name to overriden value for any overrides set on this block for this CCX. """ overrides_cache = request_cache.get_cache('ccx-overrides') if ccx not in overrides_cache: overrides = {} query = CcxFieldOverride.objects.filter( ccx=ccx, ) for override in query: block_overrides = overrides.setdefault(override.location, {}) block_overrides[override.field] = json.loads(override.value) overrides_cache[ccx] = overrides return overrides_cache[ccx]
def read(cls, user_id, course_id): """ Reads a grade from database Arguments: user_id: The user associated with the desired grade course_id: The id of the course associated with the desired grade Raises PersistentCourseGrade.DoesNotExist if applicable """ try: prefetched_grades = get_cache(cls.CACHE_NAMESPACE)[cls._cache_key(course_id)] try: return prefetched_grades[user_id] except KeyError: # user's grade is not in the prefetched list, so # assume they have no grade raise cls.DoesNotExist except KeyError: # grades were not prefetched for the course, so fetch it return cls.objects.get(user_id=user_id, course_id=course_id)
def process_response(self, __, response): """ If request is from mobile native app, then add version related info to response headers. Returns: Http response: with additional headers; 1. EDX-APP-LATEST-VERSION; if user app version < latest available version 2. EDX-APP-VERSION-LAST-SUPPORTED-DATE; if user app version < min supported version and timestamp < expiry of that version """ request_cache_dict = request_cache.get_cache(self.REQUEST_CACHE_NAME) if request_cache_dict: last_supported_date = request_cache_dict[self.LAST_SUPPORTED_DATE_HEADER] if last_supported_date != self.NO_LAST_SUPPORTED_DATE: response[self.LAST_SUPPORTED_DATE_HEADER] = last_supported_date.isoformat() latest_version = request_cache_dict[self.LATEST_VERSION_HEADER] user_app_version = request_cache_dict[self.USER_APP_VERSION] if (latest_version != self.NO_LATEST_VERSION and parsed_version(user_app_version) < parsed_version(latest_version)): response[self.LATEST_VERSION_HEADER] = latest_version return response
def cached_get_or_create(cls, blocks): prefetched = get_cache(cls._CACHE_NAMESPACE).get( cls._cache_key(blocks.course_key)) if prefetched is not None: model = prefetched.get(blocks.hash_value) if not model: model = cls.objects.create( hashed=blocks.hash_value, blocks_json=blocks.json_value, course_id=blocks.course_key, ) cls._update_cache(blocks.course_key, [model]) else: model, _ = cls.objects.get_or_create( hashed=blocks.hash_value, defaults={ u'blocks_json': blocks.json_value, u'course_id': blocks.course_key }, ) return model
def _get_version_info(self, request): """ Gets and Sets version related info in mem cache and request cache; and returns a dict of it. It sets request cache data for last_supported_date and latest_version with memcached values if exists against user app properties else computes the values for specific platform and sets it in both memcache (for next server interaction from same app version/platform) and request cache Returns: dict: Containing app version info """ user_agent = request.META.get('HTTP_USER_AGENT') if user_agent: platform = self._get_platform(request, user_agent) if platform: request_cache_dict = request_cache.get_cache(self.REQUEST_CACHE_NAME) request_cache_dict[self.USER_APP_VERSION] = platform.version last_supported_date_cache_key = self._get_cache_key_name( self.LAST_SUPPORTED_DATE_HEADER, platform.version ) latest_version_cache_key = self._get_cache_key_name(self.LATEST_VERSION_HEADER, platform.NAME) cached_data = cache.get_many([last_supported_date_cache_key, latest_version_cache_key]) last_supported_date = cached_data.get(last_supported_date_cache_key) if not last_supported_date: last_supported_date = self._get_last_supported_date(platform.NAME, platform.version) cache.set(last_supported_date_cache_key, last_supported_date, self.CACHE_TIMEOUT) request_cache_dict[self.LAST_SUPPORTED_DATE_HEADER] = last_supported_date latest_version = cached_data.get(latest_version_cache_key) if not latest_version: latest_version = self._get_latest_version(platform.NAME) cache.set(latest_version_cache_key, latest_version, self.CACHE_TIMEOUT) request_cache_dict[self.LATEST_VERSION_HEADER] = latest_version return request_cache_dict
def get_course_content_milestones(course_id, content_id, relationship, user_id=None): """ Client API operation adapter/wrapper Uses the request cache to store all of a user's milestones """ if not settings.FEATURES.get('MILESTONES_APP'): return [] if user_id is None: return milestones_api.get_course_content_milestones(course_id, content_id, relationship) request_cache_dict = request_cache.get_cache(REQUEST_CACHE_NAME) if user_id not in request_cache_dict: request_cache_dict[user_id] = {} if relationship not in request_cache_dict[user_id]: request_cache_dict[user_id][relationship] = milestones_api.get_course_content_milestones( course_key=course_id, relationship=relationship, user={"id": user_id} ) return [m for m in request_cache_dict[user_id][relationship] if m['content_id'] == content_id]
def bulk_cache_cohorts(course_key, users): """ Pre-fetches and caches the cohort assignments for the given users, for later fast retrieval by get_cohort. """ # before populating the cache with another bulk set of data, # remove previously cached entries to keep memory usage low. request_cache.clear_cache(COHORT_CACHE_NAMESPACE) cache = request_cache.get_cache(COHORT_CACHE_NAMESPACE) if is_course_cohorted(course_key): cohorts_by_user = { membership.user: membership for membership in CohortMembership.objects.filter(user__in=users, course_id=course_key).select_related('user__id') } for user, membership in cohorts_by_user.iteritems(): cache[_cohort_cache_key(user.id, course_key)] = membership.course_user_group uncohorted_users = filter(lambda u: u not in cohorts_by_user, users) else: uncohorted_users = users for user in uncohorted_users: cache[_cohort_cache_key(user.id, course_key)] = None
def get_cohort(user, course_key, assign=True, use_cached=False): """ Returns the user's cohort for the specified course. The cohort for the user is cached for the duration of a request. Pass use_cached=True to use the cached value instead of fetching from the database. Arguments: user: a Django User object. course_key: CourseKey assign (bool): if False then we don't assign a group to user use_cached (bool): Whether to use the cached value or fetch from database. Returns: A CourseUserGroup object if the course is cohorted and the User has a cohort, else None. Raises: ValueError if the CourseKey doesn't exist. """ cache = request_cache.get_cache(COHORT_CACHE_NAMESPACE) cache_key = _cohort_cache_key(user.id, course_key) if use_cached and cache_key in cache: return cache[cache_key] cache.pop(cache_key, None) # First check whether the course is cohorted (users shouldn't be in a cohort # in non-cohorted courses, but settings can change after course starts) if not is_course_cohorted(course_key): return cache.setdefault(cache_key, None) # If course is cohorted, check if the user already has a cohort. try: membership = CohortMembership.objects.get( course_id=course_key, user_id=user.id, ) return cache.setdefault(cache_key, membership.course_user_group) except CohortMembership.DoesNotExist: # Didn't find the group. If we do not want to assign, return here. if not assign: # Do not cache the cohort here, because in the next call assign # may be True, and we will have to assign the user a cohort. return None # Otherwise assign the user a cohort. try: with transaction.atomic(): # If learner has been pre-registered in a cohort, get that cohort. Otherwise assign to a random cohort. course_user_group = None for assignment in UnregisteredLearnerCohortAssignments.objects.filter( email=user.email, course_id=course_key): course_user_group = assignment.course_user_group unregistered_learner = assignment if course_user_group: unregistered_learner.delete() else: course_user_group = get_random_cohort(course_key) membership = CohortMembership.objects.create( user=user, course_user_group=course_user_group, ) return cache.setdefault(cache_key, membership.course_user_group) except IntegrityError as integrity_error: # An IntegrityError is raised when multiple workers attempt to # create the same row in one of the cohort model entries: # CourseCohort, CohortMembership. log.info( "HANDLING_INTEGRITY_ERROR: IntegrityError encountered for course '%s' and user '%s': %s", course_key, user.id, unicode(integrity_error)) return get_cohort(user, course_key, assign, use_cached)
def clear_cache(cls, course_key): """ Clears the cache of all contents for a given course. """ cache = get_cache(cls.CACHE_NAMESPACE) cache.pop(cls._cache_key(course_key), None)
def _get_metrics_cache(cls): """ Get a reference to the part of the request cache wherein we store New Relic custom metrics related to the current request. """ return request_cache.get_cache(name=REQUEST_CACHE_KEY)
def get_event_transaction_type(): """ Retrieves the current event transaction type from the request cache. """ return get_cache('event_transaction').get('type', None)
def get_event_transaction_id(): """ Retrieves the current event transaction id from the request cache. """ return get_cache('event_transaction').get('id', None)
def set_event_transaction_type(action_type): """ Takes a string and stores it in the request cache as the user action type. """ get_cache('event_transaction')['type'] = action_type
def get_cohort(user, course_key, assign=True, use_cached=False): """ Returns the user's cohort for the specified course. The cohort for the user is cached for the duration of a request. Pass use_cached=True to use the cached value instead of fetching from the database. Arguments: user: a Django User object. course_key: CourseKey assign (bool): if False then we don't assign a group to user use_cached (bool): Whether to use the cached value or fetch from database. Returns: A CourseUserGroup object if the course is cohorted and the User has a cohort, else None. Raises: ValueError if the CourseKey doesn't exist. """ cache = request_cache.get_cache(COHORT_CACHE_NAMESPACE) cache_key = _cohort_cache_key(user.id, course_key) if use_cached and cache_key in cache: return cache[cache_key] cache.pop(cache_key, None) # First check whether the course is cohorted (users shouldn't be in a cohort # in non-cohorted courses, but settings can change after course starts) if not is_course_cohorted(course_key): return cache.setdefault(cache_key, None) # If course is cohorted, check if the user already has a cohort. try: membership = CohortMembership.objects.get( course_id=course_key, user_id=user.id, ) return cache.setdefault(cache_key, membership.course_user_group) except CohortMembership.DoesNotExist: # Didn't find the group. If we do not want to assign, return here. if not assign: # Do not cache the cohort here, because in the next call assign # may be True, and we will have to assign the user a cohort. return None # Otherwise assign the user a cohort. try: with transaction.atomic(): # If learner has been pre-registered in a cohort, get that cohort. Otherwise assign to a random cohort. course_user_group = None for assignment in UnregisteredLearnerCohortAssignments.objects.filter(email=user.email, course_id=course_key): course_user_group = assignment.course_user_group unregistered_learner = assignment if course_user_group: unregistered_learner.delete() else: course_user_group = get_random_cohort(course_key) membership = CohortMembership.objects.create( user=user, course_user_group=course_user_group, ) return cache.setdefault(cache_key, membership.course_user_group) except IntegrityError as integrity_error: # An IntegrityError is raised when multiple workers attempt to # create the same row in one of the cohort model entries: # CourseCohort, CohortMembership. log.info( "HANDLING_INTEGRITY_ERROR: IntegrityError encountered for course '%s' and user '%s': %s", course_key, user.id, unicode(integrity_error) ) return get_cohort(user, course_key, assign, use_cached)
def get_user_roles(cls, user): return get_cache(cls.CACHE_NAMESPACE)[cls.CACHE_KEY][user.id]
def _cache(self): """ Namespaced request cache for tracking memory usage. """ return request_cache.get_cache(name='monitoring_memory')