fix: make bulk_email send email task handles a retryable exception (#29080)
* fix: make bulk_email send email task handles a retryable exception According to bulk_email and SMTP doc, when an error code is between (400-499) it can be retried after sometime, this commit adds a new type of exception called SMTPSenderRefused, so it can be retried **if** it's code fails under above constraint. * test: add test to handle SMTPSenderResfused Co-authored-by: Justin Hynes <jhynes@edx.org>
This commit is contained in:
committed by
GitHub
parent
f2a44ada41
commit
e1d9746d61
@@ -10,7 +10,7 @@ import re
|
||||
import time
|
||||
from collections import Counter
|
||||
from datetime import datetime
|
||||
from smtplib import SMTPConnectError, SMTPDataError, SMTPException, SMTPServerDisconnected
|
||||
from smtplib import SMTPConnectError, SMTPDataError, SMTPException, SMTPServerDisconnected, SMTPSenderRefused
|
||||
from time import sleep
|
||||
|
||||
from boto.exception import AWSConnectionError
|
||||
@@ -87,12 +87,13 @@ LIMITED_RETRY_ERRORS = (
|
||||
# An example is if email is being sent too quickly, but may succeed if sent
|
||||
# more slowly. When caught by a task, it triggers an exponential backoff and retry.
|
||||
# Retries happen continuously until the email is sent.
|
||||
# Note that the SMTPDataErrors here are only those within the 4xx range.
|
||||
# Note that the (SMTPDataErrors and SMTPSenderRefused) here are only those within the 4xx range.
|
||||
# Those not in this range (i.e. in the 5xx range) are treated as hard failures
|
||||
# and thus like SINGLE_EMAIL_FAILURE_ERRORS.
|
||||
INFINITE_RETRY_ERRORS = (
|
||||
SESMaxSendingRateExceededError, # Your account's requests/second limit has been exceeded.
|
||||
SMTPDataError,
|
||||
SMTPSenderRefused,
|
||||
)
|
||||
|
||||
# Errors that are known to indicate an inability to send any more emails,
|
||||
@@ -565,11 +566,11 @@ def _send_course_email(entry_id, email_id, to_list, global_email_context, subtas
|
||||
f"{recipient_num}/{total_recipients}, Recipient UserId: {current_recipient['pk']}"
|
||||
)
|
||||
message.send()
|
||||
except SMTPDataError as exc:
|
||||
except (SMTPDataError, SMTPSenderRefused) as exc:
|
||||
# According to SMTP spec, we'll retry error codes in the 4xx range. 5xx range indicates hard failure.
|
||||
total_recipients_failed += 1
|
||||
log.exception(
|
||||
f"BulkEmail ==> Status: Failed(SMTPDataError), Task: {parent_task_id}, SubTask: {task_id}, "
|
||||
f"BulkEmail ==> Status: Failed({exc.smtp_error}), Task: {parent_task_id}, SubTask: {task_id}, "
|
||||
f"EmailId: {email_id}, Recipient num: {recipient_num}/{total_recipients}, Recipient UserId: "
|
||||
f"{current_recipient['pk']}"
|
||||
)
|
||||
|
||||
@@ -11,7 +11,7 @@ from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import json # lint-amnesty, pylint: disable=wrong-import-order
|
||||
from itertools import chain, cycle, repeat # lint-amnesty, pylint: disable=wrong-import-order
|
||||
from smtplib import SMTPAuthenticationError, SMTPConnectError, SMTPDataError, SMTPServerDisconnected # lint-amnesty, pylint: disable=wrong-import-order
|
||||
from smtplib import SMTPAuthenticationError, SMTPConnectError, SMTPDataError, SMTPServerDisconnected, SMTPSenderRefused # lint-amnesty, pylint: disable=wrong-import-order
|
||||
from unittest.mock import Mock, patch # lint-amnesty, pylint: disable=wrong-import-order
|
||||
from uuid import uuid4 # lint-amnesty, pylint: disable=wrong-import-order
|
||||
import pytest
|
||||
@@ -411,6 +411,11 @@ class TestBulkEmailInstructorTask(InstructorTaskCourseTestCase):
|
||||
def test_retry_after_smtp_throttling_error(self):
|
||||
self._test_retry_after_unlimited_retry_error(SMTPDataError(455, "Throttling: Sending rate exceeded"))
|
||||
|
||||
def test_retry_after_smtp_sender_refused_error(self):
|
||||
self._test_retry_after_unlimited_retry_error(
|
||||
SMTPSenderRefused(421, "Throttling: Sending rate exceeded", self.instructor.email)
|
||||
)
|
||||
|
||||
def test_retry_after_ses_throttling_error(self):
|
||||
self._test_retry_after_unlimited_retry_error(
|
||||
SESMaxSendingRateExceededError(455, "Throttling: Sending rate exceeded")
|
||||
|
||||
Reference in New Issue
Block a user