Commit 3e06d681 by Awais Jibran Committed by GitHub

Merge pull request #16025 from edx/aj/handle-rate-limit-s3

BOTO:S3 handle rate limit exceed and do not expose 500 errors
parents c25925c0 79915b37
...@@ -12,6 +12,7 @@ import tempfile ...@@ -12,6 +12,7 @@ import tempfile
import ddt import ddt
import pytz import pytz
from boto.exception import BotoServerError
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core import mail from django.core import mail
...@@ -3020,6 +3021,27 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment ...@@ -3020,6 +3021,27 @@ class TestInstructorAPILevelsDataDump(SharedModuleStoreTestCase, LoginEnrollment
body.endswith('"{user_id}","41","42"\n'.format(user_id=self.students[-1].id)) body.endswith('"{user_id}","41","42"\n'.format(user_id=self.students[-1].id))
) )
@patch('lms.djangoapps.instructor_task.models.logger.error')
@patch.dict(settings.GRADES_DOWNLOAD, {'STORAGE_TYPE': 's3'})
def test_list_report_downloads_error(self, mock_error):
"""
Tests the Rate-Limit exceeded is handled and does not raise 500 error.
"""
ex_status = 503
ex_reason = 'Slow Down'
url = reverse('list_report_downloads', kwargs={'course_id': self.course.id.to_deprecated_string()})
with patch('openedx.core.storage.S3ReportStorage.listdir', side_effect=BotoServerError(ex_status, ex_reason)):
response = self.client.post(url, {})
mock_error.assert_called_with(
u'Fetching files failed for course: %s, status: %s, reason: %s',
self.course.id,
ex_status,
ex_reason,
)
res_json = json.loads(response.content)
self.assertEqual(res_json, {"downloads": []})
def test_list_report_downloads(self): def test_list_report_downloads(self):
url = reverse('list_report_downloads', kwargs={'course_id': self.course.id.to_deprecated_string()}) url = reverse('list_report_downloads', kwargs={'course_id': self.course.id.to_deprecated_string()})
with patch('lms.djangoapps.instructor_task.models.DjangoStorageReportStore.links_for') as mock_links_for: with patch('lms.djangoapps.instructor_task.models.DjangoStorageReportStore.links_for') as mock_links_for:
......
...@@ -15,9 +15,11 @@ ASSUMPTIONS: modules have unique IDs, even across different module_types ...@@ -15,9 +15,11 @@ ASSUMPTIONS: modules have unique IDs, even across different module_types
import csv import csv
import hashlib import hashlib
import json import json
import logging
import os.path import os.path
from uuid import uuid4 from uuid import uuid4
from boto.exception import BotoServerError
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
...@@ -26,6 +28,8 @@ from django.db import models, transaction ...@@ -26,6 +28,8 @@ from django.db import models, transaction
from openedx.core.djangoapps.xmodule_django.models import CourseKeyField from openedx.core.djangoapps.xmodule_django.models import CourseKeyField
from openedx.core.storage import get_storage from openedx.core.storage import get_storage
logger = logging.getLogger(__name__)
# define custom states used by InstructorTask # define custom states used by InstructorTask
QUEUING = 'QUEUING' QUEUING = 'QUEUING'
PROGRESS = 'PROGRESS' PROGRESS = 'PROGRESS'
...@@ -283,6 +287,14 @@ class DjangoStorageReportStore(ReportStore): ...@@ -283,6 +287,14 @@ class DjangoStorageReportStore(ReportStore):
# Django's FileSystemStorage fails with an OSError if the course # Django's FileSystemStorage fails with an OSError if the course
# dir does not exist; other storage types return an empty list. # dir does not exist; other storage types return an empty list.
return [] return []
except BotoServerError as ex:
logger.error(
u'Fetching files failed for course: %s, status: %s, reason: %s',
course_id,
ex.status,
ex.reason
)
return []
files = [(filename, os.path.join(course_dir, filename)) for filename in filenames] files = [(filename, os.path.join(course_dir, filename)) for filename in filenames]
files.sort(key=lambda f: self.storage.modified_time(f[1]), reverse=True) files.sort(key=lambda f: self.storage.modified_time(f[1]), reverse=True)
return [ return [
......
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