diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 35a767188a..6aa7a8242f 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -7,6 +7,8 @@ import random import re import requests +from rest_framework import status +from rest_framework.exceptions import APIException import string # pylint: disable=deprecated-module import urlparse @@ -1357,7 +1359,26 @@ def advanced_settings_handler(request, course_key_string): course_module.specialization_slug ) ) - r = requests.get(url) + try: + r = requests.get(url=url, timeout=settings.EDRAAK_PROGRAMS_API_TIMEOUT) + except requests.exceptions.Timeout: + raise APIException( + { + "status_code": status.HTTP_503_SERVICE_UNAVAILABLE, + "developer_message": "Programs specialization API have timed out." + }, + code=status.HTTP_503_SERVICE_UNAVAILABLE, + ) + except Exception: + log.exception('Something went wrong with the programs specialization API') + raise APIException( + { + "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR, + "developer_message": "Programs specialization didn't respond correctly." + }, + code=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + if r.status_code != requests.codes.ok: return JsonResponseBadRequest([ { diff --git a/cms/envs/aws.py b/cms/envs/aws.py index 2b75c8fb92..b4a7b27cfe 100644 --- a/cms/envs/aws.py +++ b/cms/envs/aws.py @@ -527,6 +527,9 @@ PROGS_URLS = ENV_TOKENS.get('PROGS_URLS', PROGS_URLS) +# API Calls Timeout +EDRAAK_PROGRAMS_API_TIMEOUT = ENV_TOKENS.get('EDRAAK_PROGRAMS_API_TIMEOUT', 3) + ################ PUSH NOTIFICATIONS ############### PARSE_KEYS = AUTH_TOKENS.get("PARSE_KEYS", {}) diff --git a/cms/envs/test.py b/cms/envs/test.py index 6ed8a06151..945ddab698 100644 --- a/cms/envs/test.py +++ b/cms/envs/test.py @@ -334,6 +334,10 @@ COUNTRIES_FIRST = [] # Turned off here to pass edx tests +EDRAAK_PROGRAMS_API_TIMEOUT = 4 + +EDRAAK_MARKETING_API_TIMEOUT = 4 + ######### custom courses ######### INSTALLED_APPS.append('openedx.core.djangoapps.ccxcon.apps.CCXConnectorConfig') FEATURES['CUSTOM_COURSES_EDX'] = True diff --git a/lms/djangoapps/course_api/helpers.py b/lms/djangoapps/course_api/helpers.py index d0a2476ff7..8d53318852 100644 --- a/lms/djangoapps/course_api/helpers.py +++ b/lms/djangoapps/course_api/helpers.py @@ -3,6 +3,9 @@ from django.conf import settings from edxmako.shortcuts import marketing_link import logging +from rest_framework import status +from rest_framework.exceptions import APIException + log = logging.getLogger(__name__) @@ -53,9 +56,29 @@ def get_marketing_data(course_key, language): marketing_root_format = marketing_link('COURSE_DETAILS_API_FORMAT') url = marketing_root_format.format(course_id=course_key) - response = requests.get(url=url, headers={ - 'Accept-Language': language, - }) + try: + response = requests.get( + url=url, + headers={'Accept-Language': language}, + timeout=settings.EDRAAK_MARKETING_API_TIMEOUT + ) + except requests.exceptions.Timeout: + raise APIException( + { + "status_code": status.HTTP_503_SERVICE_UNAVAILABLE, + "developer_message": "Marketing courses API have timed out." + }, + code=status.HTTP_503_SERVICE_UNAVAILABLE, + ) + except Exception: + log.exception('Something went wrong with the marketing courses API') + raise APIException( + { + "status_code": status.HTTP_500_INTERNAL_SERVER_ERROR, + "developer_message": "Marketing courses didn't respond correctly." + }, + code=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) if response.status_code != 200: log.warning('Could not fetch the marketing details from the API. course_key=[%s], status_code=[%s], url=[%s].', diff --git a/lms/djangoapps/course_api/tests/test_edraak_customizations.py b/lms/djangoapps/course_api/tests/test_edraak_customizations.py index 462d39d010..e341691917 100644 --- a/lms/djangoapps/course_api/tests/test_edraak_customizations.py +++ b/lms/djangoapps/course_api/tests/test_edraak_customizations.py @@ -108,7 +108,11 @@ def test_language_header_and_url(self, course_key): with mock_requests_get() as mocked_get: helpers.get_marketing_data(course_key, 'eo') self.assertEquals(mocked_get.call_count, 1) # Should be called once - mocked_get.assert_called_once_with(url=expected_url, headers={'Accept-Language': 'eo'}) + mocked_get.assert_called_once_with( + url=expected_url, + headers={'Accept-Language': 'eo'}, + timeout=4 + ) def test_valid_response(self): with mock_requests_get(status_code=200, body_json={'name': 'My Course'}): diff --git a/lms/envs/aws.py b/lms/envs/aws.py index 2990a3fdc1..d4a47c0081 100644 --- a/lms/envs/aws.py +++ b/lms/envs/aws.py @@ -708,6 +708,9 @@ EDRAAK_AUTH_REDIRECT_ORIGINS_WHITELIST = ENV_TOKENS.get("EDRAAK_AUTH_REDIRECT_ORIGINS_WHITELIST", []) EDRAAK_AUTH_REDIRECT_REGX_ORIGINS = ENV_TOKENS.get("EDRAAK_AUTH_REDIRECT_REGX_ORIGINS", []) +# API Calls Timeout +EDRAAK_MARKETING_API_TIMEOUT = ENV_TOKENS.get('EDRAAK_MARKETING_API_TIMEOUT', 3) + ##### ACCOUNT LOCKOUT DEFAULT PARAMETERS ##### MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED = ENV_TOKENS.get("MAX_FAILED_LOGIN_ATTEMPTS_ALLOWED", 5) MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS = ENV_TOKENS.get("MAX_FAILED_LOGIN_ATTEMPTS_LOCKOUT_PERIOD_SECS", 15 * 60) diff --git a/lms/envs/test.py b/lms/envs/test.py index 773ef6bf7c..390cab70f7 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -605,6 +605,8 @@ FEATURES['ENABLE_EDRAAK_LOGISTRATION'] = False # Disabled in tests by default +EDRAAK_MARKETING_API_TIMEOUT = 4 + COURSE_CATALOG_API_URL = 'https://catalog.example.com/api/v1' COMPREHENSIVE_THEME_DIRS = [REPO_ROOT / "themes", REPO_ROOT / "common/test"] diff --git a/lms/static/js/instructor_dashboard/util.js b/lms/static/js/instructor_dashboard/util.js index 6712d6702c..e60f7c1e73 100644 --- a/lms/static/js/instructor_dashboard/util.js +++ b/lms/static/js/instructor_dashboard/util.js @@ -357,15 +357,17 @@ ths, arguments ); }; - this.$running_tasks_section = findAndAssert(this.$section, '.running-tasks-section'); - this.$table_running_tasks = findAndAssert(this.$section, '.running-tasks-table'); - this.$no_tasks_message = findAndAssert(this.$section, '.no-pending-tasks-message'); - if (this.$table_running_tasks.length) { - TASK_LIST_POLL_INTERVAL = 20000; - this.reload_running_tasks_list(); - this.task_poller = new IntervalManager(TASK_LIST_POLL_INTERVAL, function() { - return ths.reload_running_tasks_list(); - }); + if (this.$section.find('.running-tasks-container').length) { + this.$running_tasks_section = findAndAssert(this.$section, '.running-tasks-section'); + this.$table_running_tasks = findAndAssert(this.$section, '.running-tasks-table'); + this.$no_tasks_message = findAndAssert(this.$section, '.no-pending-tasks-message'); + if (this.$table_running_tasks.length) { + TASK_LIST_POLL_INTERVAL = 20000; + this.reload_running_tasks_list(); + this.task_poller = new IntervalManager(TASK_LIST_POLL_INTERVAL, function () { + return ths.reload_running_tasks_list(); + }); + } } }