Files
edx-platform/lms/lib/comment_client/utils.py
Greg Price 7abaecd8b7 Improve forum error handling
CommentClientError now has sane subclasses that are meaningfully
distinct, and each subclass is handled appropriately. Errors raised by
the requests library are no longer handled by turning them into
CommentClientErrors, since there is no meaningful handling we can do,
and this way we will get more visibility into why errors are occurring.
Also, HTTP status codes from the comments service indicating client
error are correctly passed through to the client.
2013-10-28 11:23:06 -04:00

109 lines
2.8 KiB
Python

from contextlib import contextmanager
from dogapi import dog_stats_api
import json
import logging
import requests
import settings
from time import time
from uuid import uuid4
log = logging.getLogger(__name__)
def strip_none(dic):
return dict([(k, v) for k, v in dic.iteritems() if v is not None])
def strip_blank(dic):
def _is_blank(v):
return isinstance(v, str) and len(v.strip()) == 0
return dict([(k, v) for k, v in dic.iteritems() if not _is_blank(v)])
def extract(dic, keys):
if isinstance(keys, str):
return strip_none({keys: dic.get(keys)})
else:
return strip_none({k: dic.get(k) for k in keys})
def merge_dict(dic1, dic2):
return dict(dic1.items() + dic2.items())
@contextmanager
def request_timer(request_id, method, url):
start = time()
yield
end = time()
duration = end - start
dog_stats_api.histogram('comment_client.request.time', duration, end)
log.info(
"comment_client_request_log: request_id={request_id}, method={method}, "
"url={url}, duration={duration}".format(
request_id=request_id,
method=method,
url=url,
duration=duration
)
)
def perform_request(method, url, data_or_params=None, *args, **kwargs):
if data_or_params is None:
data_or_params = {}
headers = {'X-Edx-Api-Key': settings.API_KEY}
request_id = uuid4()
request_id_dict = {'request_id': request_id}
if method in ['post', 'put', 'patch']:
data = data_or_params
params = request_id_dict
else:
data = None
params = merge_dict(data_or_params, request_id_dict)
with request_timer(request_id, method, url):
response = requests.request(
method,
url,
data=data,
params=params,
headers=headers,
timeout=5
)
if 200 < response.status_code < 500:
raise CommentClientRequestError(response.text, response.status_code)
# Heroku returns a 503 when an application is in maintenance mode
elif response.status_code == 503:
raise CommentClientMaintenanceError(response.text)
elif response.status_code == 500:
raise CommentClient500Error(response.text)
else:
if kwargs.get("raw", False):
return response.text
else:
return json.loads(response.text)
class CommentClientError(Exception):
def __init__(self, msg):
self.message = msg
def __str__(self):
return repr(self.message)
class CommentClientRequestError(CommentClientError):
def __init__(self, msg, status_code=400):
super(CommentClientRequestError, self).__init__(msg)
self.status_code = status_code
class CommentClient500Error(CommentClientError):
pass
class CommentClientMaintenanceError(CommentClientError):
pass