Commit 7127ab86 by J. Cliff Dyer

Use a stable ordering for shuffled tasks.

parent af4cf7bf
...@@ -4,8 +4,8 @@ Command to compute all grades for specified courses. ...@@ -4,8 +4,8 @@ Command to compute all grades for specified courses.
from __future__ import absolute_import, division, print_function, unicode_literals from __future__ import absolute_import, division, print_function, unicode_literals
import hashlib
import logging import logging
from random import shuffle
from django.core.management.base import BaseCommand from django.core.management.base import BaseCommand
import six import six
...@@ -88,7 +88,8 @@ class Command(BaseCommand): ...@@ -88,7 +88,8 @@ class Command(BaseCommand):
Enqueue all tasks, in shuffled order. Enqueue all tasks, in shuffled order.
""" """
task_options = {'routing_key': options['routing_key']} if options.get('routing_key') else {} task_options = {'routing_key': options['routing_key']} if options.get('routing_key') else {}
for kwargs in self._shuffled_task_kwargs(options): for seq_id, kwargs in enumerate(self._shuffled_task_kwargs(options)):
kwargs['seq_id'] = seq_id
result = tasks.compute_grades_for_course_v2.apply_async(kwargs=kwargs, **task_options) result = tasks.compute_grades_for_course_v2.apply_async(kwargs=kwargs, **task_options)
log.info("Grades: Created {task_name}[{task_id}] with arguments {kwargs}".format( log.info("Grades: Created {task_name}[{task_id}] with arguments {kwargs}".format(
task_name=tasks.compute_grades_for_course.name, task_name=tasks.compute_grades_for_course.name,
...@@ -116,7 +117,7 @@ class Command(BaseCommand): ...@@ -116,7 +117,7 @@ class Command(BaseCommand):
# The dictionaries with their extra overhead will be created # The dictionaries with their extra overhead will be created
# and consumed one at a time. # and consumed one at a time.
all_args.append((six.text_type(course_key), offset, batch_size)) all_args.append((six.text_type(course_key), offset, batch_size))
shuffle(all_args) all_args.sort(key=lambda x: hashlib.md5(b'{!r}'.format(x)))
for args in all_args: for args in all_args:
yield { yield {
'course_key': args[0], 'course_key': args[0],
......
...@@ -27,6 +27,14 @@ def _sorted_by_batch(calls): ...@@ -27,6 +27,14 @@ def _sorted_by_batch(calls):
return sorted(calls, key=lambda x: (x[1]['kwargs']['course_key'], x[1]['kwargs']['offset'])) return sorted(calls, key=lambda x: (x[1]['kwargs']['course_key'], x[1]['kwargs']['offset']))
class Any(object):
"""
Dummy object that compares equal to all other objects.
"""
def __eq__(self, other):
return True
@ddt.ddt @ddt.ddt
class TestComputeGrades(SharedModuleStoreTestCase): class TestComputeGrades(SharedModuleStoreTestCase):
""" """
...@@ -100,7 +108,8 @@ class TestComputeGrades(SharedModuleStoreTestCase): ...@@ -100,7 +108,8 @@ class TestComputeGrades(SharedModuleStoreTestCase):
'course_key': course_key, 'course_key': course_key,
'batch_size': 2, 'batch_size': 2,
'offset': offset, 'offset': offset,
'estimate_first_attempted': estimate_first_attempted 'estimate_first_attempted': estimate_first_attempted,
'seq_id': Any(),
} }
self.assertEqual( self.assertEqual(
_sorted_by_batch(mock_task.apply_async.call_args_list), _sorted_by_batch(mock_task.apply_async.call_args_list),
...@@ -136,7 +145,8 @@ class TestComputeGrades(SharedModuleStoreTestCase): ...@@ -136,7 +145,8 @@ class TestComputeGrades(SharedModuleStoreTestCase):
'course_key': self.course_keys[1], 'course_key': self.course_keys[1],
'batch_size': 2, 'batch_size': 2,
'offset': 0, 'offset': 0,
'estimate_first_attempted': True 'estimate_first_attempted': True,
'seq_id': Any(),
}, },
},), },),
({ ({
...@@ -144,7 +154,8 @@ class TestComputeGrades(SharedModuleStoreTestCase): ...@@ -144,7 +154,8 @@ class TestComputeGrades(SharedModuleStoreTestCase):
'course_key': self.course_keys[1], 'course_key': self.course_keys[1],
'batch_size': 2, 'batch_size': 2,
'offset': 2, 'offset': 2,
'estimate_first_attempted': True 'estimate_first_attempted': True,
'seq_id': Any(),
}, },
},), },),
], ],
......
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