Commit 79020849 by Nimisha Asthagiri Committed by GitHub

Merge pull request #14706 from edx/neem/async-grade-enabled

Compute grades asynchronously although PersistentGrades is disabled
parents 11788282 634ac8a8
...@@ -158,21 +158,23 @@ class CourseGrade(object): ...@@ -158,21 +158,23 @@ class CourseGrade(object):
subsections_created = len(self._subsection_grade_factory._unsaved_subsection_grades) # pylint: disable=protected-access subsections_created = len(self._subsection_grade_factory._unsaved_subsection_grades) # pylint: disable=protected-access
subsections_read = subsections_total - subsections_created subsections_read = subsections_total - subsections_created
blocks_total = len(self.locations_to_scores) blocks_total = len(self.locations_to_scores)
if not read_only: if not read_only:
self._subsection_grade_factory.bulk_create_unsaved() if PersistentGradesEnabledFlag.feature_enabled(self.course.id):
grading_policy_hash = self.get_grading_policy_hash(self.course.location, self.course_structure) self._subsection_grade_factory.bulk_create_unsaved()
PersistentCourseGrade.update_or_create_course_grade( grading_policy_hash = self.get_grading_policy_hash(self.course.location, self.course_structure)
user_id=self.student.id, PersistentCourseGrade.update_or_create_course_grade(
course_id=self.course.id, user_id=self.student.id,
course_version=self.course_version, course_id=self.course.id,
course_edited_timestamp=self.course_edited_timestamp, course_version=self.course_version,
grading_policy_hash=grading_policy_hash, course_edited_timestamp=self.course_edited_timestamp,
percent_grade=self.percent, grading_policy_hash=grading_policy_hash,
letter_grade=self.letter_grade or "", percent_grade=self.percent,
passed=self.passed, letter_grade=self.letter_grade or "",
) passed=self.passed,
)
self._signal_listeners_when_grade_computed()
self._signal_listeners_when_grade_computed()
self._log_event( self._log_event(
log.warning, log.warning,
u"compute_and_update, read_only: {0}, subsections read/created: {1}/{2}, blocks accessed: {3}, total " u"compute_and_update, read_only: {0}, subsections read/created: {1}/{2}, blocks accessed: {3}, total "
......
...@@ -247,34 +247,33 @@ class SubsectionGradeFactory(object): ...@@ -247,34 +247,33 @@ class SubsectionGradeFactory(object):
""" """
# Save ourselves the extra queries if the course does not persist # Save ourselves the extra queries if the course does not persist
# subsection grades. # subsection grades.
if not PersistentGradesEnabledFlag.feature_enabled(self.course.id):
return
self._log_event(log.warning, u"update, subsection: {}".format(subsection.location), subsection) self._log_event(log.warning, u"update, subsection: {}".format(subsection.location), subsection)
calculated_grade = SubsectionGrade(subsection).init_from_structure( calculated_grade = SubsectionGrade(subsection).init_from_structure(
self.student, self.course_structure, self._submissions_scores, self._csm_scores, self.student, self.course_structure, self._submissions_scores, self._csm_scores,
) )
if only_if_higher: if PersistentGradesEnabledFlag.feature_enabled(self.course.id):
try: if only_if_higher:
grade_model = PersistentSubsectionGrade.read_grade(self.student.id, subsection.location) try:
except PersistentSubsectionGrade.DoesNotExist: grade_model = PersistentSubsectionGrade.read_grade(self.student.id, subsection.location)
pass except PersistentSubsectionGrade.DoesNotExist:
else: pass
orig_subsection_grade = SubsectionGrade(subsection).init_from_model( else:
self.student, grade_model, self.course_structure, self._submissions_scores, self._csm_scores, orig_subsection_grade = SubsectionGrade(subsection).init_from_model(
) self.student, grade_model, self.course_structure, self._submissions_scores, self._csm_scores,
if not is_score_higher_or_equal( )
orig_subsection_grade.graded_total.earned, if not is_score_higher_or_equal(
orig_subsection_grade.graded_total.possible, orig_subsection_grade.graded_total.earned,
calculated_grade.graded_total.earned, orig_subsection_grade.graded_total.possible,
calculated_grade.graded_total.possible, calculated_grade.graded_total.earned,
): calculated_grade.graded_total.possible,
return orig_subsection_grade ):
return orig_subsection_grade
grade_model = calculated_grade.update_or_create_model(self.student)
self._update_saved_subsection_grade(subsection.location, grade_model) grade_model = calculated_grade.update_or_create_model(self.student)
self._update_saved_subsection_grade(subsection.location, grade_model)
return calculated_grade return calculated_grade
@lazy @lazy
......
...@@ -25,7 +25,6 @@ from track.event_transaction_utils import ( ...@@ -25,7 +25,6 @@ from track.event_transaction_utils import (
from util.date_utils import from_timestamp from util.date_utils import from_timestamp
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from .config.models import PersistentGradesEnabledFlag
from .constants import ScoreDatabaseTableEnum from .constants import ScoreDatabaseTableEnum
from .new.subsection_grade import SubsectionGradeFactory from .new.subsection_grade import SubsectionGradeFactory
from .signals.signals import SUBSECTION_SCORE_CHANGED from .signals.signals import SUBSECTION_SCORE_CHANGED
...@@ -91,9 +90,6 @@ def _recalculate_subsection_grade(self, **kwargs): ...@@ -91,9 +90,6 @@ def _recalculate_subsection_grade(self, **kwargs):
""" """
try: try:
course_key = CourseLocator.from_string(kwargs['course_id']) course_key = CourseLocator.from_string(kwargs['course_id'])
if not PersistentGradesEnabledFlag.feature_enabled(course_key):
return
scored_block_usage_key = UsageKey.from_string(kwargs['usage_id']).replace(course_key=course_key) scored_block_usage_key = UsageKey.from_string(kwargs['usage_id']).replace(course_key=course_key)
newrelic.agent.add_custom_parameter('course_id', unicode(course_key)) newrelic.agent.add_custom_parameter('course_id', unicode(course_key))
......
...@@ -27,6 +27,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, chec ...@@ -27,6 +27,7 @@ from xmodule.modulestore.tests.factories import CourseFactory, ItemFactory, chec
from lms.djangoapps.grades.config.models import PersistentGradesEnabledFlag from lms.djangoapps.grades.config.models import PersistentGradesEnabledFlag
from lms.djangoapps.grades.constants import ScoreDatabaseTableEnum from lms.djangoapps.grades.constants import ScoreDatabaseTableEnum
from lms.djangoapps.grades.models import PersistentCourseGrade, PersistentSubsectionGrade
from lms.djangoapps.grades.signals.signals import PROBLEM_WEIGHTED_SCORE_CHANGED from lms.djangoapps.grades.signals.signals import PROBLEM_WEIGHTED_SCORE_CHANGED
from lms.djangoapps.grades.tasks import recalculate_subsection_grade_v3, RECALCULATE_GRADE_DELAY from lms.djangoapps.grades.tasks import recalculate_subsection_grade_v3, RECALCULATE_GRADE_DELAY
...@@ -203,14 +204,34 @@ class RecalculateSubsectionGradeTest(ModuleStoreTestCase): ...@@ -203,14 +204,34 @@ class RecalculateSubsectionGradeTest(ModuleStoreTestCase):
{self.sequential.location, accessible_seq.location}, {self.sequential.location, accessible_seq.location},
) )
@ddt.data(ModuleStoreEnum.Type.mongo, ModuleStoreEnum.Type.split) @ddt.data(
def test_persistent_grades_not_enabled_on_course(self, default_store): (ModuleStoreEnum.Type.mongo, 1, 9),
(ModuleStoreEnum.Type.split, 3, 8),
)
@ddt.unpack
def test_persistent_grades_not_enabled_on_course(self, default_store, num_mongo_queries, num_sql_queries):
with self.store.default_store(default_store): with self.store.default_store(default_store):
self.set_up_course(enable_persistent_grades=False) self.set_up_course(enable_persistent_grades=False)
self.assertFalse(PersistentGradesEnabledFlag.feature_enabled(self.course.id)) with check_mongo_calls(num_mongo_queries):
with check_mongo_calls(0): with self.assertNumQueries(num_sql_queries):
with self.assertNumQueries(0): self._apply_recalculate_subsection_grade()
with self.assertRaises(PersistentCourseGrade.DoesNotExist):
PersistentCourseGrade.read_course_grade(self.user.id, self.course.id)
self.assertEqual(len(PersistentSubsectionGrade.bulk_read_grades(self.user.id, self.course.id)), 0)
@ddt.data(
(ModuleStoreEnum.Type.mongo, 1, 22),
(ModuleStoreEnum.Type.split, 3, 21),
)
@ddt.unpack
def test_persistent_grades_enabled_on_course(self, default_store, num_mongo_queries, num_sql_queries):
with self.store.default_store(default_store):
self.set_up_course(enable_persistent_grades=True)
with check_mongo_calls(num_mongo_queries):
with self.assertNumQueries(num_sql_queries):
self._apply_recalculate_subsection_grade() self._apply_recalculate_subsection_grade()
self.assertIsNotNone(PersistentCourseGrade.read_course_grade(self.user.id, self.course.id))
self.assertGreater(len(PersistentSubsectionGrade.bulk_read_grades(self.user.id, self.course.id)), 0)
@patch('lms.djangoapps.grades.signals.signals.SUBSECTION_SCORE_CHANGED.send') @patch('lms.djangoapps.grades.signals.signals.SUBSECTION_SCORE_CHANGED.send')
@patch('lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory.update') @patch('lms.djangoapps.grades.new.subsection_grade.SubsectionGradeFactory.update')
......
...@@ -1775,7 +1775,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase): ...@@ -1775,7 +1775,7 @@ class TestCertificateGeneration(InstructorTaskModuleTestCase):
'failed': 3, 'failed': 3,
'skipped': 2 'skipped': 2
} }
with self.assertNumQueries(169): with self.assertNumQueries(168):
self.assertCertificatesGenerated(task_input, expected_results) self.assertCertificatesGenerated(task_input, expected_results)
expected_results = { expected_results = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment