From c48ed39df51da55f61bbb4f7cf7902d8c842d5b5 Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Tue, 28 Jun 2022 16:54:29 +0200 Subject: [PATCH] :sparkles: [open-zaak/open-zaak#1206] Send email if notifs fail --- src/nrc/api/tasks.py | 60 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 9 deletions(-) diff --git a/src/nrc/api/tasks.py b/src/nrc/api/tasks.py index 7edf6ac7..7cebeefa 100644 --- a/src/nrc/api/tasks.py +++ b/src/nrc/api/tasks.py @@ -1,7 +1,11 @@ import json import logging +from urllib.parse import urlparse +from django.conf import settings +from django.core.mail import send_mail from django.core.serializers.json import DjangoJSONEncoder +from django.urls import reverse from django.utils.translation import gettext_lazy as _ import requests @@ -11,7 +15,7 @@ from vng_api_common.notifications.models import NotificationsConfig from nrc.celery import app -from nrc.datamodel.models import Abonnement, NotificatieResponse +from nrc.datamodel.models import Abonnement, Notificatie, NotificatieResponse logger = logging.getLogger(__name__) @@ -29,7 +33,7 @@ def add_autoretry_behaviour(task, **options): if autoretry_for and not hasattr(task, "_orig_run"): @wraps(task.run) - def run(*args, **kwargs): + def run(sub_id: int, msg: dict, **kwargs): config = NotificationsConfig.get_solo() max_retries = config.notification_delivery_max_retries retry_backoff = config.notification_delivery_retry_backoff @@ -38,7 +42,7 @@ def run(*args, **kwargs): task.max_retries = max_retries try: - return task._orig_run(*args, **kwargs) + return task._orig_run(sub_id, msg, **kwargs) except Ignore: # If Ignore signal occurs task shouldn't be retried, # even if it suits autoretry_for list @@ -59,11 +63,17 @@ def run(*args, **kwargs): task, "override_max_retries", max_retries ) - ret = task.retry(exc=exc, **retry_kwargs) - # Stop propagation - if hasattr(task, "override_max_retries"): - delattr(task, "override_max_retries") - raise ret + try: + ret = task.retry(exc=exc, **retry_kwargs) + # Stop propagation + if hasattr(task, "override_max_retries"): + delattr(task, "override_max_retries") + raise ret + except autoretry_for as exc: + # Final retry failed, send email + send_email_to_admins.delay(sub_id, kwargs.get("notificatie_id")) + except: + raise task._orig_run, task.run = task.run, run @@ -72,6 +82,38 @@ class NotificationException(Exception): pass +@app.task +def send_email_to_admins(sub_id: int, notificatie_id: int) -> None: + subscription = Abonnement.objects.get(pk=sub_id) + notification = Notificatie.objects.get(pk=notificatie_id) + + config = NotificationsConfig.get_solo() + + if not config.failed_notification_admin_recipients: + return + + parsed = urlparse(config.api_root) + notifications_changelist = reverse("admin:datamodel_notificatie_changelist") + + body = """ + Notification {notificatie_id} to subscriber {sub_uuid} failed. + + See {admin_url} for more info + """.format( + notificatie_id=notification.uuid, + sub_uuid=subscription.uuid, + admin_url=f"{parsed.scheme}://{parsed.netloc}{notifications_changelist}", + ) + + send_mail( + f"Failed notification - {notification.uuid}", + body, + settings.DEFAULT_FROM_EMAIL, + config.failed_notification_admin_recipients, + fail_silently=False, + ) + + @app.task def deliver_message(sub_id: int, msg: dict, **kwargs) -> None: """ @@ -117,7 +159,7 @@ def deliver_message(sub_id: int, msg: dict, **kwargs) -> None: notificatie_id=notificatie_id, abonnement=sub, attempt=kwargs.get("attempt", 1), - **response_init_kwargs + **response_init_kwargs, )