stages/email: Implement MonitoredTask, but only for failed emails

This commit is contained in:
Jens Langhammer 2020-10-16 14:31:01 +02:00
parent 4ac87d8739
commit 8fedd9ec07
2 changed files with 48 additions and 24 deletions

View File

@ -69,10 +69,14 @@ class TaskInfo:
class MonitoredTask(Task): class MonitoredTask(Task):
"""Task which can save its state to the cache""" """Task which can save its state to the cache"""
# For tasks that should only be listed if they failed, set this to False
save_on_success: bool
_result: TaskResult _result: TaskResult
def __init__(self, *args, **kwargs) -> None: def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.save_on_success = True
self._result = TaskResult(status=TaskResultStatus.ERROR, messages=[]) self._result = TaskResult(status=TaskResultStatus.ERROR, messages=[])
def set_status(self, result: TaskResult): def set_status(self, result: TaskResult):
@ -83,6 +87,7 @@ class MonitoredTask(Task):
def after_return( def after_return(
self, status, retval, task_id, args: List[Any], kwargs: Dict[str, Any], einfo self, status, retval, task_id, args: List[Any], kwargs: Dict[str, Any], einfo
): ):
if self.save_on_success:
TaskInfo( TaskInfo(
task_name=self.__name__, task_name=self.__name__,
task_description=self.__doc__, task_description=self.__doc__,

View File

@ -1,11 +1,14 @@
"""email stage tasks""" """email stage tasks"""
from email.utils import make_msgid
from smtplib import SMTPException from smtplib import SMTPException
from typing import Any, Dict, List from typing import Any, Dict, List
from celery import group from celery import group
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
from django.core.mail.utils import DNS_NAME
from structlog import get_logger from structlog import get_logger
from passbook.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus
from passbook.root.celery import CELERY_APP from passbook.root.celery import CELERY_APP
from passbook.stages.email.models import EmailStage from passbook.stages.email.models import EmailStage
@ -16,7 +19,7 @@ def send_mails(stage: EmailStage, *messages: List[EmailMultiAlternatives]):
"""Wrapper to convert EmailMessage to dict and send it from worker""" """Wrapper to convert EmailMessage to dict and send it from worker"""
tasks = [] tasks = []
for message in messages: for message in messages:
tasks.append(_send_mail_task.s(stage.pk, message.__dict__)) tasks.append(send_mail.s(stage.pk, message.__dict__))
lazy_group = group(*tasks) lazy_group = group(*tasks)
promise = lazy_group() promise = lazy_group()
return promise return promise
@ -29,11 +32,13 @@ def send_mails(stage: EmailStage, *messages: List[EmailMultiAlternatives]):
ConnectionError, ConnectionError,
), ),
retry_backoff=True, retry_backoff=True,
base=MonitoredTask,
) )
# pylint: disable=unused-argument def send_mail(self: MonitoredTask, email_stage_pk: int, message: Dict[Any, Any]):
def _send_mail_task(self, email_stage_pk: int, message: Dict[Any, Any]):
"""Send Email according to EmailStage parameters from background worker. """Send Email according to EmailStage parameters from background worker.
Automatically retries if message couldn't be sent.""" Automatically retries if message couldn't be sent."""
self.save_on_success = False
try:
stage: EmailStage = EmailStage.objects.get(pk=email_stage_pk) stage: EmailStage = EmailStage.objects.get(pk=email_stage_pk)
backend = stage.backend backend = stage.backend
backend.open() backend.open()
@ -43,5 +48,19 @@ def _send_mail_task(self, email_stage_pk: int, message: Dict[Any, Any]):
for key, value in message.items(): for key, value in message.items():
setattr(message_object, key, value) setattr(message_object, key, value)
message_object.from_email = stage.from_address message_object.from_email = stage.from_address
# Because we use the Message-ID as UID for the task, manually assign it
message_id = make_msgid(DNS_NAME)
message_object.extra_headers["Message-ID"] = message_id
LOGGER.debug("Sending mail", to=message_object.to) LOGGER.debug("Sending mail", to=message_object.to)
stage.backend.send_messages([message_object]) stage.backend.send_messages([message_object])
self.set_status(
TaskResult(
TaskResultStatus.SUCCESSFUL,
messages=["Successfully sent Mail."],
uid=message_id,
)
)
except (SMTPException, ConnectionError) as exc:
self.set_status(TaskResult(TaskResultStatus.ERROR, [str(exc)], exc))
raise exc