Skip to content

Commit e213977

Browse files
committed
Add error handling to the email sending task
1 parent 5b47a0c commit e213977

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

styleguide_example/emails/services.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import random
2+
13
from django.db import transaction
24
from django.db.models.query import QuerySet
35
from django.core.mail import EmailMultiAlternatives
46
from django.utils import timezone
7+
from django.conf import settings
58

69
from styleguide_example.core.exceptions import ApplicationError
710

@@ -11,11 +14,32 @@
1114
from styleguide_example.emails.tasks import email_send as email_send_task
1215

1316

17+
@transaction.atomic
18+
def email_failed(email: Email) -> Email:
19+
if email.status != Email.Status.SENDING:
20+
raise ApplicationError(f"Cannot fail non-sending emails. Current status is {email.status}")
21+
22+
email, _ = model_update(
23+
instance=email,
24+
fields=["status"],
25+
data={
26+
"status": Email.Status.FAILED
27+
}
28+
)
29+
return email
30+
31+
1432
@transaction.atomic
1533
def email_send(email: Email) -> Email:
1634
if email.status != Email.Status.SENDING:
1735
raise ApplicationError(f"Cannot send non-ready emails. Current status is {email.status}")
1836

37+
if settings.EMAIL_SENDING_FAILURE_TRIGGER:
38+
failure_dice = random.uniform(0, 1)
39+
40+
if failure_dice <= settings.EMAIL_SENDING_FAILURE_RATE:
41+
raise ApplicationError("Email sending failure triggered.")
42+
1943
subject = email.subject
2044
from_email = "styleguide-example@hacksoft.io"
2145
to = email.to
@@ -45,7 +69,7 @@ def email_send_all(emails: QuerySet[Email]):
4569
4670
We don't want to decorate with @transaction.atomic,
4771
since we are executing updates, 1 by 1, in a separate atomic block,
48-
so we can trigger transaction.on_commit for each email.
72+
so we can trigger transaction.on_commit for each email, separately.
4973
"""
5074
for email in emails:
5175
with transaction.atomic():

styleguide_example/emails/tasks.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
11
from celery import shared_task
2+
from celery.utils.log import get_task_logger
23

34
from styleguide_example.emails.models import Email
45

56

6-
@shared_task
7-
def email_send(email_id):
8-
# TODO: Add error handling
7+
logger = get_task_logger(__name__)
8+
9+
10+
def _email_send_failure(self, exc, task_id, args, kwargs, einfo):
11+
email_id = args[0]
12+
email = Email.objects.get(id=email_id)
13+
14+
from styleguide_example.emails.services import email_failed
15+
16+
email_failed(email)
17+
18+
19+
@shared_task(bind=True, on_failure=_email_send_failure)
20+
def email_send(self, email_id):
921
email = Email.objects.get(id=email_id)
1022

1123
from styleguide_example.emails.services import email_send
12-
email_send(email)
24+
25+
try:
26+
email_send(email)
27+
except Exception as exc:
28+
# https://docs.celeryq.dev/en/stable/userguide/tasks.html#retrying
29+
logger.warning(f"Exception occurred while sending email: {exc}")
30+
self.retry(exc=exc, countdown=5)

0 commit comments

Comments
 (0)