Commit 4062b94a by Clinton Blackburn

Fixed Celery Serialization Bug

CourseLocator is not JSON-serializable. Passing course keys as Unicode instead when scheduling tasks to update course structure.
parent 78079213
...@@ -299,7 +299,7 @@ class CourseStructureTests(CourseDetailMixin, CourseViewTestsMixin, ModuleStoreT ...@@ -299,7 +299,7 @@ class CourseStructureTests(CourseDetailMixin, CourseViewTestsMixin, ModuleStoreT
super(CourseStructureTests, self).setUp() super(CourseStructureTests, self).setUp()
# Ensure course structure exists for the course # Ensure course structure exists for the course
update_course_structure(self.course.id) update_course_structure(unicode(self.course.id))
def test_get(self): def test_get(self):
""" """
......
...@@ -192,7 +192,7 @@ class CourseStructure(CourseViewMixin, RetrieveAPIView): ...@@ -192,7 +192,7 @@ class CourseStructure(CourseViewMixin, RetrieveAPIView):
return super(CourseStructure, self).retrieve(request, *args, **kwargs) return super(CourseStructure, self).retrieve(request, *args, **kwargs)
except models.CourseStructure.DoesNotExist: except models.CourseStructure.DoesNotExist:
# If we don't have data stored, generate it and return a 503. # If we don't have data stored, generate it and return a 503.
models.update_course_structure.delay(self.course.id) models.update_course_structure.delay(unicode(self.course.id))
return Response(status=503, headers={'Retry-After': '120'}) return Response(status=503, headers={'Retry-After': '120'})
def get_object(self, queryset=None): def get_object(self, queryset=None):
......
...@@ -39,7 +39,7 @@ class Command(BaseCommand): ...@@ -39,7 +39,7 @@ class Command(BaseCommand):
for course_key in course_keys: for course_key in course_keys:
try: try:
update_course_structure(course_key) update_course_structure(unicode(course_key))
except Exception as e: except Exception as e:
logger.error('An error occurred while generating course structure for %s: %s', unicode(course_key), e) logger.error('An error occurred while generating course structure for %s: %s', unicode(course_key), e)
......
...@@ -4,7 +4,7 @@ import logging ...@@ -4,7 +4,7 @@ import logging
from celery.task import task from celery.task import task
from django.dispatch import receiver from django.dispatch import receiver
from model_utils.models import TimeStampedModel from model_utils.models import TimeStampedModel
from opaque_keys.edx.locator import CourseLocator from opaque_keys.edx.keys import CourseKey
from xmodule.modulestore.django import modulestore, SignalHandler from xmodule.modulestore.django import modulestore, SignalHandler
from util.models import CompressedTextField from util.models import CompressedTextField
...@@ -60,7 +60,7 @@ def generate_course_structure(course_key): ...@@ -60,7 +60,7 @@ def generate_course_structure(course_key):
def listen_for_course_publish(sender, course_key, **kwargs): def listen_for_course_publish(sender, course_key, **kwargs):
# Note: The countdown=0 kwarg is set to to ensure the method below does not attempt to access the course # Note: The countdown=0 kwarg is set to to ensure the method below does not attempt to access the course
# before the signal emitter has finished all operations. This is also necessary to ensure all tests pass. # before the signal emitter has finished all operations. This is also necessary to ensure all tests pass.
update_course_structure.delay(course_key, countdown=0) update_course_structure.delay(unicode(course_key), countdown=0)
@task() @task()
...@@ -68,9 +68,12 @@ def update_course_structure(course_key): ...@@ -68,9 +68,12 @@ def update_course_structure(course_key):
""" """
Regenerates and updates the course structure (in the database) for the specified course. Regenerates and updates the course structure (in the database) for the specified course.
""" """
if not isinstance(course_key, CourseLocator): # Ideally we'd like to accept a CourseLocator; however, CourseLocator is not JSON-serializable (by default) so
logger.error('update_course_structure requires a CourseLocator. Given %s.', type(course_key)) # Celery's delayed tasks fail to start. For this reason, callers should pass the course key as a Unicode string.
return if not isinstance(course_key, basestring):
raise ValueError('course_key must be a string. {} is not acceptable.'.format(type(course_key)))
course_key = CourseKey.from_string(course_key)
try: try:
structure = generate_course_structure(course_key) structure = generate_course_structure(course_key)
......
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