diff --git a/common/lib/xmodule/xmodule/modulestore/__init__.py b/common/lib/xmodule/xmodule/modulestore/__init__.py index c167c25422..6949472011 100644 --- a/common/lib/xmodule/xmodule/modulestore/__init__.py +++ b/common/lib/xmodule/xmodule/modulestore/__init__.py @@ -272,12 +272,20 @@ class BulkOperationsMixin(object): dirty = self._end_outermost_bulk_operation(bulk_ops_record, structure_key) - self._clear_bulk_ops_record(structure_key) + # The bulk op has ended. However, the signal tasks below still need to use the + # built-up bulk op information (if the signals trigger tasks in the same thread). + # So re-nest until the signals are sent. + bulk_ops_record.nest() if emit_signals and dirty: self.send_bulk_published_signal(bulk_ops_record, structure_key) self.send_bulk_library_updated_signal(bulk_ops_record, structure_key) + # Signals are sent. Now unnest and clear the bulk op for good. + bulk_ops_record.unnest() + + self._clear_bulk_ops_record(structure_key) + def _is_in_bulk_operation(self, course_key, ignore_case=False): """ Return whether a bulk operation is active on `course_key`. diff --git a/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py b/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py index b41bf268d6..dfafc920e1 100644 --- a/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py +++ b/common/lib/xmodule/xmodule/modulestore/tests/test_mixed_modulestore.py @@ -2015,8 +2015,11 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup): course_key = course.id def _clear_bulk_ops_record(course_key): # pylint: disable=unused-argument - """ Check if the signal has been fired. """ - self.assertEqual(receiver.call_count, 0) + """ + Check if the signal has been fired. + The course_published signal fires before the _clear_bulk_ops_record. + """ + self.assertEqual(receiver.call_count, 1) with patch.object( self.store.thread_cache.default_store, '_clear_bulk_ops_record', wraps=_clear_bulk_ops_record