diff --git a/common/lib/xmodule/xmodule/contentstore/mongo.py b/common/lib/xmodule/xmodule/contentstore/mongo.py index f942b25002..d03de7a8fc 100644 --- a/common/lib/xmodule/xmodule/contentstore/mongo.py +++ b/common/lib/xmodule/xmodule/contentstore/mongo.py @@ -26,6 +26,10 @@ class MongoContentStore(ContentStore): :param collection: ignores but provided for consistency w/ other doc_store_config patterns """ logging.debug('Using MongoDB for static content serving at host={0} port={1} db={2}'.format(host, port, db)) + + # Remove the replicaSet parameter. + kwargs.pop('replicaSet', None) + _db = pymongo.database.Database( pymongo.MongoClient( host=host, diff --git a/common/lib/xmodule/xmodule/modulestore/django.py b/common/lib/xmodule/xmodule/modulestore/django.py index a8c73d7f3d..8db59c8ba2 100644 --- a/common/lib/xmodule/xmodule/modulestore/django.py +++ b/common/lib/xmodule/xmodule/modulestore/django.py @@ -20,6 +20,8 @@ if not settings.configured: from django.core.cache import get_cache, InvalidCacheBackendError import django.dispatch import django.utils + +from pymongo import ReadPreference from xmodule.contentstore.django import contentstore from xmodule.modulestore.draft_and_published import BranchSettingMixin from xmodule.modulestore.mixed import MixedModuleStore @@ -156,6 +158,9 @@ def create_modulestore_instance( else: xb_user_service = None + if 'read_preference' in doc_store_config: + doc_store_config['read_preference'] = getattr(ReadPreference, doc_store_config['read_preference']) + return class_( contentstore=content_store, metadata_inheritance_cache_subsystem=metadata_inheritance_cache, diff --git a/common/lib/xmodule/xmodule/modulestore/mongo/base.py b/common/lib/xmodule/xmodule/modulestore/mongo/base.py index b49391f9f8..9f62ee5ef4 100644 --- a/common/lib/xmodule/xmodule/modulestore/mongo/base.py +++ b/common/lib/xmodule/xmodule/modulestore/mongo/base.py @@ -552,6 +552,9 @@ class MongoModuleStore(ModuleStoreDraftAndPublished, ModuleStoreWriteBase, Mongo """ Create & open the connection, authenticate, and provide pointers to the collection """ + # Remove the replicaSet parameter. + kwargs.pop('replicaSet', None) + self.database = MongoProxy( pymongo.database.Database( pymongo.MongoClient( diff --git a/common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py b/common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py index 160e2f8ce6..289c871af1 100644 --- a/common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py +++ b/common/lib/xmodule/xmodule/modulestore/split_mongo/mongo_connection.py @@ -81,16 +81,19 @@ class MongoConnection(object): """ Create & open the connection, authenticate, and provide pointers to the collections """ + if kwargs.get('replicaSet') is None: + kwargs.pop('replicaSet', None) + mongo_class = pymongo.MongoClient + else: + mongo_class = pymongo.MongoReplicaSetClient + _client = mongo_class( + host=host, + port=port, + tz_aware=tz_aware, + **kwargs + ) self.database = MongoProxy( - pymongo.database.Database( - pymongo.MongoClient( - host=host, - port=port, - tz_aware=tz_aware, - **kwargs - ), - db - ), + pymongo.database.Database(_client, db), wait_time=retry_wait_time ) diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 03e256c742..3981e59ff4 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -908,40 +908,47 @@ def _invoke_xblock_handler(request, course_id, usage_id, handler, suffix): if error_msg: return JsonResponse(object={'success': error_msg}, status=413) - instance, tracking_context = get_module_by_usage_id(request, course_id, usage_id) - - # Name the transaction so that we can view XBlock handlers separately in - # New Relic. The suffix is necessary for XModule handlers because the - # "handler" in those cases is always just "xmodule_handler". - nr_tx_name = "{}.{}".format(instance.__class__.__name__, handler) - nr_tx_name += "/{}".format(suffix) if suffix else "" - newrelic.agent.set_transaction_name(nr_tx_name, group="Python/XBlock/Handler") - - tracking_context_name = 'module_callback_handler' - req = django_to_webob_request(request) + # Make a CourseKey from the course_id, raising a 404 upon parse error. try: - with tracker.get_tracker().context(tracking_context_name, tracking_context): - resp = instance.handle(handler, req, suffix) - - except NoSuchHandlerError: - log.exception("XBlock %s attempted to access missing handler %r", instance, handler) + course_key = CourseKey.from_string(course_id) + except InvalidKeyError: raise Http404 - # If we can't find the module, respond with a 404 - except NotFoundError: - log.exception("Module indicating to user that request doesn't exist") - raise Http404 + with modulestore().bulk_operations(course_key): + instance, tracking_context = get_module_by_usage_id(request, course_id, usage_id) - # For XModule-specific errors, we log the error and respond with an error message - except ProcessingError as err: - log.warning("Module encountered an error while processing AJAX call", - exc_info=True) - return JsonResponse(object={'success': err.args[0]}, status=200) + # Name the transaction so that we can view XBlock handlers separately in + # New Relic. The suffix is necessary for XModule handlers because the + # "handler" in those cases is always just "xmodule_handler". + nr_tx_name = "{}.{}".format(instance.__class__.__name__, handler) + nr_tx_name += "/{}".format(suffix) if suffix else "" + newrelic.agent.set_transaction_name(nr_tx_name, group="Python/XBlock/Handler") - # If any other error occurred, re-raise it to trigger a 500 response - except Exception: - log.exception("error executing xblock handler") - raise + tracking_context_name = 'module_callback_handler' + req = django_to_webob_request(request) + try: + with tracker.get_tracker().context(tracking_context_name, tracking_context): + resp = instance.handle(handler, req, suffix) + + except NoSuchHandlerError: + log.exception("XBlock %s attempted to access missing handler %r", instance, handler) + raise Http404 + + # If we can't find the module, respond with a 404 + except NotFoundError: + log.exception("Module indicating to user that request doesn't exist") + raise Http404 + + # For XModule-specific errors, we log the error and respond with an error message + except ProcessingError as err: + log.warning("Module encountered an error while processing AJAX call", + exc_info=True) + return JsonResponse(object={'success': err.args[0]}, status=200) + + # If any other error occurred, re-raise it to trigger a 500 response + except Exception: + log.exception("error executing xblock handler") + raise return webob_to_django_response(resp)