Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion rpc/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@
VersionInfoSerializer,
check_user_has_role,
)
from .tasks import publish_rfctobe_task, send_mail_task, validate_metadata_task
from .tasks.mail import send_mail_task
from .tasks.metadata import validate_metadata_task
from .tasks.publish import publish_rfctobe_task
from .utils import VersionInfo, create_rpc_related_document, get_or_create_draft_by_name

logger = logging.getLogger(__name__)
Expand Down
Empty file added rpc/tasks/__init__.py
Empty file.
55 changes: 55 additions & 0 deletions rpc/tasks/mail.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Copyright The IETF Trust 2026, All Rights Reserved
from celery import shared_task
from celery.utils.log import get_task_logger
from django.db.models import F

from utils.task_utils import RetryTask

from ..models import MailMessage

logger = get_task_logger(__name__)


class EmailTask(RetryTask):
max_retries = 4 * 24 * 3 # every 15 minutes for 3 days
# When retries run out, the admins will be emailed. There's a good chance that
# sending that mail will fail also, but it's what we have for now.


class SendEmailError(Exception):
pass


@shared_task(base=EmailTask, autoretry_for=(SendEmailError,))
def send_mail_task(message_id):
message = MailMessage.objects.get(pk=message_id)
email = message.as_emailmessage()
try:
email.send()
except Exception as err:
logger.error(
"Sending with subject '%s' failed: %s",
message.subject,
str(err),
)
raise SendEmailError from err
else:
# Flag that the message was sent in case the task fails before deleting it
MailMessage.objects.filter(pk=message_id).update(sent=True)
finally:
# Always increment this
MailMessage.objects.filter(pk=message_id).update(attempts=F("attempts") + 1)
# Get friendly name of msgtype
message_type = dict(MailMessage.MessageType.choices)[message.msgtype]
comment = f"Sent {message_type} email with Message-ID={message.message_id}"
if message.rfctobe is not None:
message.rfctobe.rpcdocumentcomment_set.create(
comment=comment,
by=message.sender,
)
if message.draft is not None:
message.draft.rpcdocumentcomment_set.create(
comment=comment,
by=message.sender,
)
message.delete()
76 changes: 4 additions & 72 deletions rpc/tasks.py → rpc/tasks/metadata.py
Original file line number Diff line number Diff line change
@@ -1,67 +1,14 @@
# Copyright The IETF Trust 2025-2026, All Rights Reserved
# Copyright The IETF Trust 2026, All Rights Reserved
from celery import shared_task
from celery.utils.log import get_task_logger
from django.db.models import F

from utils.task_utils import RetryTask

from .lifecycle.metadata import Metadata
from .lifecycle.publication import (
PublicationError,
TemporaryPublicationError,
publish_rfctobe,
)
from .lifecycle.repo import GithubRepository
from .models import MailMessage, MetadataValidationResults, RfcToBe
from ..lifecycle.metadata import Metadata
from ..lifecycle.repo import GithubRepository
from ..models import MetadataValidationResults, RfcToBe

logger = get_task_logger(__name__)


class EmailTask(RetryTask):
max_retries = 4 * 24 * 3 # every 15 minutes for 3 days
# When retries run out, the admins will be emailed. There's a good chance that
# sending that mail will fail also, but it's what we have for now.


class SendEmailError(Exception):
pass


@shared_task(base=EmailTask, autoretry_for=(SendEmailError,))
def send_mail_task(message_id):
message = MailMessage.objects.get(pk=message_id)
email = message.as_emailmessage()
try:
email.send()
except Exception as err:
logger.error(
"Sending with subject '%s' failed: %s",
message.subject,
str(err),
)
raise SendEmailError from err
else:
# Flag that the message was sent in case the task fails before deleting it
MailMessage.objects.filter(pk=message_id).update(sent=True)
finally:
# Always increment this
MailMessage.objects.filter(pk=message_id).update(attempts=F("attempts") + 1)
# Get friendly name of msgtype
message_type = dict(MailMessage.MessageType.choices)[message.msgtype]
comment = f"Sent {message_type} email with Message-ID={message.message_id}"
if message.rfctobe is not None:
message.rfctobe.rpcdocumentcomment_set.create(
comment=comment,
by=message.sender,
)
if message.draft is not None:
message.draft.rpcdocumentcomment_set.create(
comment=comment,
by=message.sender,
)
message.delete()


@shared_task(bind=True)
def validate_metadata_task(self, rfc_to_be_id):
"""
Expand Down Expand Up @@ -137,18 +84,3 @@ def _save_metadata_results(rfc_to_be, head_sha, metadata, status, detail=None):
detail = str(e)
status = MetadataValidationResults.Status.FAILED
_save_metadata_results(rfc_to_be, head_sha, metadata, status, detail)


class PublishRfcToBeTask(RetryTask):
pass


@shared_task(
bind=True,
base=PublishRfcToBeTask,
throws=(RfcToBe.DoesNotExist, PublicationError),
autoretry_for=(TemporaryPublicationError,),
)
def publish_rfctobe_task(self, rfctobe_id, expected_head):
rfctobe = RfcToBe.objects.get(pk=rfctobe_id)
publish_rfctobe(rfctobe, expected_head=expected_head)
29 changes: 29 additions & 0 deletions rpc/tasks/publish.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright The IETF Trust 2026, All Rights Reserved
from celery import shared_task
from celery.utils.log import get_task_logger

from utils.task_utils import RetryTask

from ..lifecycle.publication import (
PublicationError,
TemporaryPublicationError,
publish_rfctobe,
)
from ..models import RfcToBe

logger = get_task_logger(__name__)


class PublishRfcToBeTask(RetryTask):
pass


@shared_task(
bind=True,
base=PublishRfcToBeTask,
throws=(RfcToBe.DoesNotExist, PublicationError),
autoretry_for=(TemporaryPublicationError,),
)
def publish_rfctobe_task(self, rfctobe_id, expected_head):
rfctobe = RfcToBe.objects.get(pk=rfctobe_id)
publish_rfctobe(rfctobe, expected_head=expected_head)