Skip to content

Commit

Permalink
Send notifications via django-q2
Browse files Browse the repository at this point in the history
  • Loading branch information
hmpf committed Sep 20, 2023
1 parent a3d0c65 commit 2b41824
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 41 deletions.
5 changes: 2 additions & 3 deletions src/argus/incident/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,11 @@ def ready(self):
close_token_incident,
delete_associated_user,
delete_associated_event,
task_send_notification, # noqa
task_background_send_notification,
enqueue_event_for_notification,
)

post_delete.connect(delete_associated_user, "argus_incident.SourceSystem")
post_delete.connect(delete_associated_event, "argus_incident.Acknowledgement")
post_delete.connect(close_token_incident, "authtoken.Token")
post_save.connect(close_token_incident, "authtoken.Token")
post_save.connect(task_background_send_notification, "argus_incident.Event", dispatch_uid="send_notification")
post_save.connect(enqueue_event_for_notification, "argus_incident.Event", dispatch_uid="send_notification")
37 changes: 27 additions & 10 deletions src/argus/incident/signals.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,52 @@
import logging

from django.db.models import Q
from django.utils import timezone

from rest_framework.authtoken.models import Token
from django_q.tasks import async_task

from argus.notificationprofile.media import send_notifications_to_users
from argus.notificationprofile.media import background_send_notification
from argus.notificationprofile.media import find_destinations_for_event
from argus.notificationprofile.media import send_notification
from argus.notificationprofile.media import are_notifications_turned_on

from .models import (
Acknowledgement, ChangeEvent, Event, Incident, SourceSystem, Tag,
Acknowledgement,
ChangeEvent,
Event,
Incident,
SourceSystem,
Tag,
get_or_create_default_instances,
)


__all__ = [
"enqueue_event_for_notification",
"delete_associated_user",
"send_notification",
"delete_associated_event",
"close_token_incident",
]

LOG = logging.getLogger(__name__)

def delete_associated_user(sender, instance: SourceSystem, *args, **kwargs):
if hasattr(instance, "user") and instance.user:
instance.user.delete()

def enqueue_event_for_notification(sender, instance: Event, *args, **kwargs):
if not are_notifications_turned_on():
return

def task_send_notification(sender, instance: Event, *args, **kwargs):
send_notifications_to_users(instance)
destinations = find_destinations_for_event(instance)
if destinations:
LOG.info('Notification: will be sending notification for "%s"', instance)
async_task(send_notification, destinations, instance, group="notifications")
else:
LOG.debug("Notification: no destinations to send notification to")


def task_background_send_notification(sender, instance: Event, *args, **kwargs):
send_notifications_to_users(instance, send=background_send_notification)
def delete_associated_user(sender, instance: SourceSystem, *args, **kwargs):
if hasattr(instance, "user") and instance.user:
instance.user.delete()


def delete_associated_event(sender, instance: Acknowledgement, *args, **kwargs):
Expand Down
4 changes: 0 additions & 4 deletions src/argus/incident/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,6 @@
TicketPluginException,
TicketSettingsException,
)
from argus.notificationprofile.media import (
send_notifications_to_users,
background_send_notification,
)
from argus.util.datetime_utils import INFINITY_REPR
from argus.util.signals import bulk_changed
from argus.util.utils import import_class_from_dotted_path
Expand Down
22 changes: 9 additions & 13 deletions src/argus/notificationprofile/media/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
from __future__ import annotations

import logging
from multiprocessing import Process
from typing import TYPE_CHECKING

from django.conf import settings
from django.db import connections
from rest_framework.exceptions import ValidationError

from ..models import DestinationConfig, Media, NotificationProfile
Expand All @@ -25,9 +23,9 @@


__all__ = [
"are_notifications_turned_on",
"api_safely_get_medium_object",
"send_notification",
"background_send_notification",
"find_destinations_for_event",
"find_destinations_for_many_events",
"send_notifications_to_users",
Expand All @@ -41,6 +39,13 @@
MEDIA_CLASSES_DICT = {media_class.MEDIA_SLUG: media_class for media_class in MEDIA_CLASSES}


def are_notifications_turned_on():
if not getattr(settings, "SEND_NOTIFICATIONS", False):
LOG.info("Notification: turned off sitewide, not sending any")
return False
return True


def api_safely_get_medium_object(media_slug):
try:
obj = MEDIA_CLASSES_DICT[media_slug]
Expand All @@ -65,14 +70,6 @@ def send_notification(destinations: Iterable[DestinationConfig], *events: Iterab
LOG.info('Notification: sent event "%s" to "%s"', event, medium.MEDIA_SLUG)


def background_send_notification(destinations: Iterable[DestinationConfig], *events: Event):
connections.close_all()
LOG.info("Notification: backgrounded: about to send %i events", len(events))
p = Process(target=send_notification, args=(destinations, *events))
p.start()
return p


def find_destinations_for_event(event: Event):
destinations = set()
incident = event.incident
Expand All @@ -96,8 +93,7 @@ def send_notifications_to_users(*events: Iterable[Event], send=send_notification
if not events:
LOG.warn("Notification: no events to send, programming error?")
return
if not getattr(settings, "SEND_NOTIFICATIONS", False):
LOG.info("Notification: turned off sitewide, not sending any")
if not are_notifications_turned_on():
return
# TODO: only send one notification per medium per user
LOG.debug('Fallback filter set to "%s"', getattr(settings, "ARGUS_FALLBACK_FILTER", {}))
Expand Down
6 changes: 4 additions & 2 deletions src/argus/notificationprofile/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,10 @@ def save(self, *args, **kwargs):
class FilterWrapper:
TRINARY_FILTERS = ("open", "acked", "stateful")

def __init__(self, filterblob):
def __init__(self, filterblob, user=None):
self.fallback_filter = getattr(settings, "ARGUS_FALLBACK_FILTER", {})
self.filter = filterblob
self.user = user # simplifies debugging, set breakpoint for specific user

def _get_tristate(self, tristate):
fallback_filter = self.fallback_filter.get(tristate, None)
Expand Down Expand Up @@ -178,7 +179,8 @@ class Meta:

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.filter_wrapper = FilterWrapper(self.filter)
user = getattr(self, "user", None)
self.filter_wrapper = FilterWrapper(self.filter, user)

def __str__(self):
return f"{self.name} [{self.filter}]"
Expand Down
15 changes: 6 additions & 9 deletions src/argus/util/testing.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from django.db.models.signals import post_save

from argus.incident.signals import send_notification
from argus.incident.signals import background_send_notification
from argus.incident.models import Event
# import the signal sender (aka. post_save)

# import the signal receivers

__all__ = [
"disconnect_signals",
Expand All @@ -15,10 +12,10 @@


def disconnect_signals():
post_save.disconnect(send_notification, Event, dispatch_uid="send_notification")
post_save.disconnect(background_send_notification, Event, dispatch_uid="send_notification")
# signal.disconnect(receiver)
pass


def connect_signals():
post_save.connect(send_notification, Event, dispatch_uid="send_notification")
post_save.connect(background_send_notification, Event, dispatch_uid="send_notification")
# signal.connect(receiver)
pass

0 comments on commit 2b41824

Please sign in to comment.