Commit dd4bab3c by PaulWattenberger

ECOM-5065 Don't treat invalid email response from Sailthru as retryable error

parent 97489999
......@@ -125,7 +125,8 @@ def add_email_marketing_cookies(sender, response=None, user=None,
log.error("No cookie returned attempting to obtain cookie from Sailthru for %s", user.email)
else:
error = sailthru_response.get_error()
log.error("Error attempting to obtain cookie from Sailthru: %s", error.get_message())
# generally invalid email address
log.info("Error attempting to obtain cookie from Sailthru: %s", error.get_message())
return response
......
......@@ -47,10 +47,11 @@ def update_user(self, sailthru_vars, email, new_user=False, activation=False):
if not sailthru_response.is_ok():
error = sailthru_response.get_error()
# put out error and schedule retry
log.error("Error attempting to add/update user in Sailthru: %s", error.get_message())
raise self.retry(countdown=email_config.sailthru_retry_interval,
max_retries=email_config.sailthru_max_retries)
if _retryable_sailthru_error(error):
raise self.retry(countdown=email_config.sailthru_retry_interval,
max_retries=email_config.sailthru_max_retries)
return
# if activating user, send welcome email
if activation and email_config.sailthru_activation_template:
......@@ -66,8 +67,10 @@ def update_user(self, sailthru_vars, email, new_user=False, activation=False):
if not sailthru_response.is_ok():
error = sailthru_response.get_error()
# probably a disabled template, just put out error message
log.error("Error attempting to send welcome email to user in Sailthru: %s", error.get_message())
if _retryable_sailthru_error(error):
raise self.retry(countdown=email_config.sailthru_retry_interval,
max_retries=email_config.sailthru_max_retries)
# pylint: disable=not-callable
......@@ -103,8 +106,9 @@ def update_user_email(self, new_email, old_email):
if not sailthru_response.is_ok():
error = sailthru_response.get_error()
log.error("Error attempting to update user email address in Sailthru: %s", error.get_message())
raise self.retry(countdown=email_config.sailthru_retry_interval,
max_retries=email_config.sailthru_max_retries)
if _retryable_sailthru_error(error):
raise self.retry(countdown=email_config.sailthru_retry_interval,
max_retries=email_config.sailthru_max_retries)
def _create_sailthru_user_parm(sailthru_vars, email, new_user, email_config):
......@@ -254,7 +258,7 @@ def _record_purchase(sailthru_client, email, item, message_id, options):
if not sailthru_response.is_ok():
error = sailthru_response.get_error()
log.error("Error attempting to record purchase in Sailthru: %s", error.get_message())
return False
return not _retryable_sailthru_error(error)
except SailthruClientError as exc:
log.error("Exception attempting to record purchase for %s in Sailthru - %s", email, unicode(exc))
......@@ -305,8 +309,8 @@ def _update_unenrolled_list(sailthru_client, email, course_url, unenroll):
sailthru_response = sailthru_client.api_get("user", {"id": email, "fields": {"vars": 1}})
if not sailthru_response.is_ok():
error = sailthru_response.get_error()
log.error("Error attempting to read user record from Sailthru: %s", error.get_message())
return False
log.info("Error attempting to read user record from Sailthru: %s", error.get_message())
return not _retryable_sailthru_error(error)
response_json = sailthru_response.json
......@@ -333,8 +337,8 @@ def _update_unenrolled_list(sailthru_client, email, course_url, unenroll):
if not sailthru_response.is_ok():
error = sailthru_response.get_error()
log.error("Error attempting to update user record in Sailthru: %s", error.get_message())
return False
log.info("Error attempting to update user record in Sailthru: %s", error.get_message())
return not _retryable_sailthru_error(error)
# everything worked
return True
......@@ -342,3 +346,16 @@ def _update_unenrolled_list(sailthru_client, email, course_url, unenroll):
except SailthruClientError as exc:
log.error("Exception attempting to update user record for %s in Sailthru - %s", email, unicode(exc))
return False
def _retryable_sailthru_error(error):
""" Return True if error should be retried.
9: Retryable internal error
43: Rate limiting response
others: Not retryable
See: https://getstarted.sailthru.com/new-for-developers-overview/api/api-response-errors/
"""
code = error.get_error_code()
return code == 9 or code == 43
......@@ -172,6 +172,30 @@ class EmailMarketingTests(TestCase):
update_user.delay({}, self.user.email, activation=True)
self.assertTrue(mock_log_error.called)
@patch('email_marketing.tasks.update_user.retry')
@patch('email_marketing.tasks.log.error')
@patch('email_marketing.tasks.SailthruClient.api_post')
def test_update_user_error_retryable(self, mock_sailthru, mock_log_error, mock_retry):
"""
Ensure that retryable error is retried
"""
mock_sailthru.return_value = SailthruResponse(JsonResponse({'error': 43, 'errormsg': 'Got an error'}))
update_user.delay({}, self.user.email)
self.assertTrue(mock_log_error.called)
self.assertTrue(mock_retry.called)
@patch('email_marketing.tasks.update_user.retry')
@patch('email_marketing.tasks.log.error')
@patch('email_marketing.tasks.SailthruClient.api_post')
def test_update_user_error_nonretryable(self, mock_sailthru, mock_log_error, mock_retry):
"""
Ensure that non-retryable error is not retried
"""
mock_sailthru.return_value = SailthruResponse(JsonResponse({'error': 1, 'errormsg': 'Got an error'}))
update_user.delay({}, self.user.email)
self.assertTrue(mock_log_error.called)
self.assertFalse(mock_retry.called)
@patch('email_marketing.tasks.log.error')
@patch('email_marketing.tasks.SailthruClient.api_post')
def test_just_return_tasks(self, mock_sailthru, mock_log_error):
......@@ -284,11 +308,12 @@ class EmailMarketingTests(TestCase):
self.assertEquals(userparms['keys']['email'], TEST_EMAIL)
@patch('email_marketing.tasks.log.error')
@patch('email_marketing.tasks.log.info')
@patch('email_marketing.tasks.SailthruClient.purchase')
@patch('email_marketing.tasks.SailthruClient.api_get')
@patch('email_marketing.tasks.SailthruClient.api_post')
def test_update_course_enrollment(self, mock_sailthru_api_post,
mock_sailthru_api_get, mock_sailthru_purchase, mock_log_error):
mock_sailthru_api_get, mock_sailthru_purchase, mock_log_info, mock_log_error):
"""
test async method in task posts enrolls and purchases
"""
......@@ -347,14 +372,14 @@ class EmailMarketingTests(TestCase):
# test unsupported event
mock_sailthru_purchase.side_effect = SailthruClientError
mock_log_error.reset_mock()
mock_log_info.reset_mock()
update_course_enrollment.delay(TEST_EMAIL,
self.course_url,
EnrollStatusChange.upgrade_start,
'verified',
course_id=self.course_id_string,
message_id='cookie_bid')
self.assertFalse(mock_log_error.called)
self.assertFalse(mock_log_info.called)
# test error updating user
mock_sailthru_api_get.return_value = SailthruResponse(JsonResponse({'error': 100, 'errormsg': 'Got an error'}))
......@@ -364,7 +389,7 @@ class EmailMarketingTests(TestCase):
'verified',
course_id=self.course_id_string,
message_id='cookie_bid')
self.assertTrue(mock_log_error.called)
self.assertTrue(mock_log_info.called)
@patch('email_marketing.tasks.SailthruClient')
def test_get_course_content(self, mock_sailthru_client):
......@@ -417,13 +442,13 @@ class EmailMarketingTests(TestCase):
# test get error from Sailthru
mock_sailthru_client.api_get.return_value = \
SailthruResponse(JsonResponse({'error': 100, 'errormsg': 'Got an error'}))
SailthruResponse(JsonResponse({'error': 43, 'errormsg': 'Got an error'}))
self.assertFalse(_update_unenrolled_list(mock_sailthru_client, TEST_EMAIL,
self.course_url, False))
# test post error from Sailthru
mock_sailthru_client.api_post.return_value = \
SailthruResponse(JsonResponse({'error': 100, 'errormsg': 'Got an error'}))
SailthruResponse(JsonResponse({'error': 43, 'errormsg': 'Got an error'}))
mock_sailthru_client.api_get.return_value = \
SailthruResponse(JsonResponse({'vars': {'unenrolled': [self.course_url]}}))
self.assertFalse(_update_unenrolled_list(mock_sailthru_client, TEST_EMAIL,
......
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